You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2019/09/03 08:51:34 UTC
[incubator-echarts] branch master updated: Add tool to run all
tests automatically. (#11154)
This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
The following commit(s) were added to refs/heads/master by this push:
new 4af1779 Add tool to run all tests automatically. (#11154)
4af1779 is described below
commit 4af177937bac7e6e6429b17e27d9e5ab520d5e28
Author: Yi Shen <bm...@gmail.com>
AuthorDate: Tue Sep 3 16:51:27 2019 +0800
Add tool to run all tests automatically. (#11154)
* test: Run the tests automatically for visual regression test.
* doc: Update CONTRIBUTING doc for test section
* test: Improve visual regression test UI
* test: Add tests select and run control in dashboard
* test: Use child process to run test. Add logs in dashboard
* test: Fix some logic issue of controlling test in dashboard.
* test(autorun): Improve Dashboard UI
* test: Remove puppeteer from devDependencies
* Update package-lock.json
* style: fix code style.
---
.github/CONTRIBUTING.md | 10 +-
package-lock.json | 1504 +++++++++++++++++++------------------
package.json | 11 +-
test/runTest/blacklist.js | 4 +
test/runTest/cli.js | 271 +++++++
test/runTest/client/client.css | 163 ++++
test/runTest/client/client.js | 182 +++++
test/runTest/client/index.html | 168 +++++
test/runTest/compareScreenshot.js | 41 +
test/runTest/config.js | 4 +
test/runTest/runtime/main.js | 53 ++
test/runTest/runtime/shim.js | 9 +
test/runTest/server.js | 127 ++++
test/runTest/store.js | 78 ++
test/runTest/util.js | 66 ++
15 files changed, 1951 insertions(+), 740 deletions(-)
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 96e432e..4577ff4 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -103,7 +103,15 @@ Then, open the test cases under `~/workspace/echarts/test` in Web browser. You c

-### 4. Make a pull request
+### 4. Run test
+
+```bash
+node test/runTest/cli.js
+```
+
+It will run all the test cases under `~/workspace/echarts/test` automatically to compare with the previous version. You can use this to check if your code bring some breaking change.
+
+### 5. Make a pull request
Fork ECharts project into your own project. Checkout a branch from master branch named `fix-xxxx`, where xxxx is the issue id related. If there's no related issue, you need to create one in most cases to describe what's wrong or what new feature is required.
diff --git a/package-lock.json b/package-lock.json
index bbc437b..0c8483c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,18 +1,16 @@
{
"name": "echarts",
- "version": "4.2.1-rc.2",
+ "version": "4.2.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/code-frame": {
- "version": "7.0.0-beta.31",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.31.tgz",
- "integrity": "sha512-yd7CkUughvHQoEahQqcMdrZw6o/6PwUxiRkfZuVDVHCDe77mysD/suoNyk5mK6phTnRW1kyIbPHyCJgxw++LXg==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
+ "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
"dev": true,
"requires": {
- "chalk": "^2.0.0",
- "esutils": "^2.0.2",
- "js-tokens": "^3.0.0"
+ "@babel/highlight": "7.5.0"
}
},
"@babel/core": {
@@ -21,77 +19,68 @@
"integrity": "sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/generator": "^7.3.4",
- "@babel/helpers": "^7.2.0",
- "@babel/parser": "^7.3.4",
- "@babel/template": "^7.2.2",
- "@babel/traverse": "^7.3.4",
- "@babel/types": "^7.3.4",
- "convert-source-map": "^1.1.0",
- "debug": "^4.1.0",
- "json5": "^2.1.0",
- "lodash": "^4.17.11",
- "resolve": "^1.3.2",
- "semver": "^5.4.1",
- "source-map": "^0.5.0"
+ "@babel/code-frame": "7.5.5",
+ "@babel/generator": "7.5.5",
+ "@babel/helpers": "7.5.5",
+ "@babel/parser": "7.5.5",
+ "@babel/template": "7.4.4",
+ "@babel/traverse": "7.5.5",
+ "@babel/types": "7.5.5",
+ "convert-source-map": "1.6.0",
+ "debug": "4.1.1",
+ "json5": "2.1.0",
+ "lodash": "4.17.15",
+ "resolve": "1.12.0",
+ "semver": "5.7.1",
+ "source-map": "0.5.7"
},
"dependencies": {
- "@babel/code-frame": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
- "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.0.0"
- }
- },
"@babel/template": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz",
- "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==",
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz",
+ "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/parser": "^7.2.2",
- "@babel/types": "^7.2.2"
+ "@babel/code-frame": "7.5.5",
+ "@babel/parser": "7.5.5",
+ "@babel/types": "7.5.5"
}
},
"@babel/types": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz",
- "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz",
+ "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==",
"dev": true,
"requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
+ "esutils": "2.0.3",
+ "lodash": "4.17.15",
+ "to-fast-properties": "2.0.0"
}
}
}
},
"@babel/generator": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz",
- "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.5.tgz",
+ "integrity": "sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==",
"dev": true,
"requires": {
- "@babel/types": "^7.3.4",
- "jsesc": "^2.5.1",
- "lodash": "^4.17.11",
- "source-map": "^0.5.0",
- "trim-right": "^1.0.1"
+ "@babel/types": "7.5.5",
+ "jsesc": "2.5.2",
+ "lodash": "4.17.15",
+ "source-map": "0.5.7",
+ "trim-right": "1.0.1"
},
"dependencies": {
"@babel/types": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz",
- "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz",
+ "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==",
"dev": true,
"requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
+ "esutils": "2.0.3",
+ "lodash": "4.17.15",
+ "to-fast-properties": "2.0.0"
}
}
}
@@ -102,40 +91,31 @@
"integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==",
"dev": true,
"requires": {
- "@babel/helper-get-function-arity": "^7.0.0",
- "@babel/template": "^7.1.0",
- "@babel/types": "^7.0.0"
+ "@babel/helper-get-function-arity": "7.0.0",
+ "@babel/template": "7.4.4",
+ "@babel/types": "7.5.5"
},
"dependencies": {
- "@babel/code-frame": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
- "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.0.0"
- }
- },
"@babel/template": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz",
- "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==",
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz",
+ "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/parser": "^7.2.2",
- "@babel/types": "^7.2.2"
+ "@babel/code-frame": "7.5.5",
+ "@babel/parser": "7.5.5",
+ "@babel/types": "7.5.5"
}
},
"@babel/types": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz",
- "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz",
+ "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==",
"dev": true,
"requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
+ "esutils": "2.0.3",
+ "lodash": "4.17.15",
+ "to-fast-properties": "2.0.0"
}
}
}
@@ -146,18 +126,18 @@
"integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==",
"dev": true,
"requires": {
- "@babel/types": "^7.0.0"
+ "@babel/types": "7.5.5"
},
"dependencies": {
"@babel/types": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz",
- "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz",
+ "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==",
"dev": true,
"requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
+ "esutils": "2.0.3",
+ "lodash": "4.17.15",
+ "to-fast-properties": "2.0.0"
}
}
}
@@ -169,7 +149,7 @@
"dev": true,
"requires": {
"@babel/types": "7.0.0-beta.31",
- "lodash": "^4.2.0"
+ "lodash": "4.17.15"
}
},
"@babel/helper-module-transforms": {
@@ -182,7 +162,7 @@
"@babel/helper-simple-access": "7.0.0-beta.31",
"@babel/template": "7.0.0-beta.31",
"@babel/types": "7.0.0-beta.31",
- "lodash": "^4.2.0"
+ "lodash": "4.17.15"
}
},
"@babel/helper-simple-access": {
@@ -193,98 +173,81 @@
"requires": {
"@babel/template": "7.0.0-beta.31",
"@babel/types": "7.0.0-beta.31",
- "lodash": "^4.2.0"
+ "lodash": "4.17.15"
}
},
"@babel/helper-split-export-declaration": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz",
- "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==",
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz",
+ "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==",
"dev": true,
"requires": {
- "@babel/types": "^7.0.0"
+ "@babel/types": "7.5.5"
},
"dependencies": {
"@babel/types": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz",
- "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz",
+ "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==",
"dev": true,
"requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
+ "esutils": "2.0.3",
+ "lodash": "4.17.15",
+ "to-fast-properties": "2.0.0"
}
}
}
},
"@babel/helpers": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.3.1.tgz",
- "integrity": "sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.5.5.tgz",
+ "integrity": "sha512-nRq2BUhxZFnfEn/ciJuhklHvFOqjJUD5wpx+1bxUF2axL9C+v4DE/dmp5sT2dKnpOs4orZWzpAZqlCy8QqE/7g==",
"dev": true,
"requires": {
- "@babel/template": "^7.1.2",
- "@babel/traverse": "^7.1.5",
- "@babel/types": "^7.3.0"
+ "@babel/template": "7.4.4",
+ "@babel/traverse": "7.5.5",
+ "@babel/types": "7.5.5"
},
"dependencies": {
- "@babel/code-frame": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
- "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.0.0"
- }
- },
"@babel/template": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz",
- "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==",
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz",
+ "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/parser": "^7.2.2",
- "@babel/types": "^7.2.2"
+ "@babel/code-frame": "7.5.5",
+ "@babel/parser": "7.5.5",
+ "@babel/types": "7.5.5"
}
},
"@babel/types": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz",
- "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz",
+ "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==",
"dev": true,
"requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
+ "esutils": "2.0.3",
+ "lodash": "4.17.15",
+ "to-fast-properties": "2.0.0"
}
}
}
},
"@babel/highlight": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
- "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
+ "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
"dev": true,
"requires": {
- "chalk": "^2.0.0",
- "esutils": "^2.0.2",
- "js-tokens": "^4.0.0"
- },
- "dependencies": {
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
- }
+ "chalk": "2.4.2",
+ "esutils": "2.0.3",
+ "js-tokens": "4.0.0"
}
},
"@babel/parser": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz",
- "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz",
+ "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==",
"dev": true
},
"@babel/template": {
@@ -296,44 +259,54 @@
"@babel/code-frame": "7.0.0-beta.31",
"@babel/types": "7.0.0-beta.31",
"babylon": "7.0.0-beta.31",
- "lodash": "^4.2.0"
- }
- },
- "@babel/traverse": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz",
- "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/generator": "^7.3.4",
- "@babel/helper-function-name": "^7.1.0",
- "@babel/helper-split-export-declaration": "^7.0.0",
- "@babel/parser": "^7.3.4",
- "@babel/types": "^7.3.4",
- "debug": "^4.1.0",
- "globals": "^11.1.0",
- "lodash": "^4.17.11"
+ "lodash": "4.17.15"
},
"dependencies": {
"@babel/code-frame": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
- "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
+ "version": "7.0.0-beta.31",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.31.tgz",
+ "integrity": "sha512-yd7CkUughvHQoEahQqcMdrZw6o/6PwUxiRkfZuVDVHCDe77mysD/suoNyk5mK6phTnRW1kyIbPHyCJgxw++LXg==",
"dev": true,
"requires": {
- "@babel/highlight": "^7.0.0"
+ "chalk": "2.4.2",
+ "esutils": "2.0.3",
+ "js-tokens": "3.0.2"
}
},
+ "js-tokens": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+ "dev": true
+ }
+ }
+ },
+ "@babel/traverse": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.5.tgz",
+ "integrity": "sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "7.5.5",
+ "@babel/generator": "7.5.5",
+ "@babel/helper-function-name": "7.1.0",
+ "@babel/helper-split-export-declaration": "7.4.4",
+ "@babel/parser": "7.5.5",
+ "@babel/types": "7.5.5",
+ "debug": "4.1.1",
+ "globals": "11.12.0",
+ "lodash": "4.17.15"
+ },
+ "dependencies": {
"@babel/types": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz",
- "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz",
+ "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==",
"dev": true,
"requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
+ "esutils": "2.0.3",
+ "lodash": "4.17.15",
+ "to-fast-properties": "2.0.0"
}
}
}
@@ -344,11 +317,50 @@
"integrity": "sha512-exAHB+NeFGxkfQ5dSUD03xl3zYGneeSk2Mw2ldTt/nTvYxuDiuSp3DlxgUBgzbdTFG4fbwPk0WtKWOoTXCmNGg==",
"dev": true,
"requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.2.0",
- "to-fast-properties": "^2.0.0"
+ "esutils": "2.0.3",
+ "lodash": "4.17.15",
+ "to-fast-properties": "2.0.0"
}
},
+ "accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "dev": true,
+ "requires": {
+ "mime-types": "2.1.24",
+ "negotiator": "0.6.2"
+ },
+ "dependencies": {
+ "mime-db": {
+ "version": "1.40.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
+ "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.24",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
+ "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.40.0"
+ }
+ }
+ }
+ },
+ "acorn": {
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
+ "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
+ "dev": true
+ },
+ "after": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
+ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=",
+ "dev": true
+ },
"amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
@@ -362,9 +374,15 @@
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
- "color-convert": "^1.9.0"
+ "color-convert": "1.9.3"
}
},
+ "arraybuffer.slice": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
+ "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
+ "dev": true
+ },
"assert": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
@@ -374,25 +392,64 @@
"util": "0.10.3"
}
},
+ "async-limiter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+ "dev": true
+ },
"babylon": {
"version": "7.0.0-beta.31",
"resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.31.tgz",
"integrity": "sha512-6lm2mV3S51yEnKmQQNnswoABL1U1H1KHoCCVwdwI3hvIv+W7ya4ki7Aw4o4KxtUHjNKkK5WpZb22rrMMOcJXJQ==",
"dev": true
},
+ "backo2": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
+ "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
+ "dev": true
+ },
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
+ "base64-arraybuffer": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
+ "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
+ "dev": true
+ },
+ "base64id": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
+ "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=",
+ "dev": true
+ },
+ "better-assert": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
+ "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
+ "dev": true,
+ "requires": {
+ "callsite": "1.0.0"
+ }
+ },
+ "blob": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
+ "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==",
+ "dev": true
+ },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
- "balanced-match": "^1.0.0",
+ "balanced-match": "1.0.0",
"concat-map": "0.0.1"
}
},
@@ -419,15 +476,27 @@
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
"dev": true
},
+ "bytes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
+ "dev": true
+ },
+ "callsite": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
+ "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
+ "dev": true
+ },
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
+ "ansi-styles": "3.2.1",
+ "escape-string-regexp": "1.0.5",
+ "supports-color": "5.5.0"
}
},
"color-convert": {
@@ -451,21 +520,51 @@
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
"dev": true
},
+ "component-bind": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
+ "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=",
+ "dev": true
+ },
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+ "dev": true
+ },
+ "component-inherit": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
+ "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=",
+ "dev": true
+ },
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
+ "content-disposition": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
+ "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=",
+ "dev": true
+ },
"convert-source-map": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
"integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
"dev": true,
"requires": {
- "safe-buffer": "~5.1.1"
+ "safe-buffer": "5.1.2"
}
},
+ "cookie": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=",
+ "dev": true
+ },
"coordtransform": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/coordtransform/-/coordtransform-2.0.2.tgz",
@@ -478,7 +577,7 @@
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
- "ms": "^2.1.1"
+ "ms": "2.1.2"
}
},
"deep-is": {
@@ -487,6 +586,86 @@
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
"dev": true
},
+ "engine.io": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.3.2.tgz",
+ "integrity": "sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w==",
+ "dev": true,
+ "requires": {
+ "accepts": "1.3.7",
+ "base64id": "1.0.0",
+ "cookie": "0.3.1",
+ "debug": "3.1.0",
+ "engine.io-parser": "2.1.3",
+ "ws": "6.1.4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "engine.io-client": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.2.tgz",
+ "integrity": "sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ==",
+ "dev": true,
+ "requires": {
+ "component-emitter": "1.2.1",
+ "component-inherit": "0.0.3",
+ "debug": "3.1.0",
+ "engine.io-parser": "2.1.3",
+ "has-cors": "1.1.0",
+ "indexof": "0.0.1",
+ "parseqs": "0.0.5",
+ "parseuri": "0.0.5",
+ "ws": "6.1.4",
+ "xmlhttprequest-ssl": "1.5.5",
+ "yeast": "0.1.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "engine.io-parser": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz",
+ "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==",
+ "dev": true,
+ "requires": {
+ "after": "0.8.2",
+ "arraybuffer.slice": "0.0.7",
+ "base64-arraybuffer": "0.1.5",
+ "blob": "0.0.5",
+ "has-binary2": "1.0.3"
+ }
+ },
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -499,11 +678,11 @@
"integrity": "sha1-skaq6CnOc9WeLFVyc1nt0cEwqBs=",
"dev": true,
"requires": {
- "esprima": "^2.7.1",
- "estraverse": "^1.9.1",
- "esutils": "^2.0.2",
- "optionator": "^0.8.1",
- "source-map": "~0.2.0"
+ "esprima": "2.7.2",
+ "estraverse": "1.9.3",
+ "esutils": "2.0.3",
+ "optionator": "0.8.2",
+ "source-map": "0.2.0"
},
"dependencies": {
"estraverse": {
@@ -519,7 +698,7 @@
"dev": true,
"optional": true,
"requires": {
- "amdefine": ">=0.0.4"
+ "amdefine": "1.0.1"
}
}
}
@@ -536,10 +715,16 @@
"integrity": "sha1-9srKcokzqFDvkGYdDheYK6RxEaI=",
"dev": true
},
+ "estree-walker": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz",
+ "integrity": "sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig==",
+ "dev": true
+ },
"esutils": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
- "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
"fast-levenshtein": {
@@ -548,17 +733,26 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
+ "fast-url-parser": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
+ "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=",
+ "dev": true,
+ "requires": {
+ "punycode": "1.4.1"
+ }
+ },
"fs-extra": {
"version": "0.26.7",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz",
"integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=",
"dev": true,
"requires": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^2.1.0",
- "klaw": "^1.0.0",
- "path-is-absolute": "^1.0.0",
- "rimraf": "^2.2.8"
+ "graceful-fs": "4.2.2",
+ "jsonfile": "2.4.0",
+ "klaw": "1.3.1",
+ "path-is-absolute": "1.0.1",
+ "rimraf": "2.7.1"
}
},
"fs.realpath": {
@@ -573,23 +767,38 @@
"integrity": "sha1-OyCjV//89GuzhK7W+K6aZH/basQ=",
"dev": true,
"requires": {
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "2 || 3",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
+ "inflight": "1.0.6",
+ "inherits": "2.0.1",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
}
},
"globals": {
- "version": "11.11.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz",
- "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==",
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
"dev": true
},
"graceful-fs": {
- "version": "4.1.15",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
- "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
+ "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==",
+ "dev": true
+ },
+ "has-binary2": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
+ "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
+ "dev": true,
+ "requires": {
+ "isarray": "2.0.1"
+ }
+ },
+ "has-cors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
+ "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
"dev": true
},
"has-flag": {
@@ -598,14 +807,20 @@
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
+ "indexof": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+ "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
+ "dev": true
+ },
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
- "once": "^1.3.0",
- "wrappy": "1"
+ "once": "1.4.0",
+ "wrappy": "1.0.2"
}
},
"inherits": {
@@ -620,10 +835,16 @@
"integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
"dev": true
},
+ "isarray": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
+ "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=",
+ "dev": true
+ },
"js-tokens": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
- "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"jsesc": {
@@ -638,7 +859,7 @@
"integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
"dev": true,
"requires": {
- "minimist": "^1.2.0"
+ "minimist": "1.2.0"
}
},
"jsonfile": {
@@ -647,7 +868,7 @@
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
"dev": true,
"requires": {
- "graceful-fs": "^4.1.6"
+ "graceful-fs": "4.2.2"
}
},
"klaw": {
@@ -656,7 +877,7 @@
"integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
"dev": true,
"requires": {
- "graceful-fs": "^4.1.9"
+ "graceful-fs": "4.2.2"
}
},
"levn": {
@@ -665,23 +886,53 @@
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
"dev": true,
"requires": {
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2"
+ "prelude-ls": "1.1.2",
+ "type-check": "0.3.2"
}
},
"lodash": {
- "version": "4.17.11",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
- "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+ "dev": true
+ },
+ "lolex": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz",
+ "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==",
+ "dev": true
+ },
+ "magic-string": {
+ "version": "0.22.5",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz",
+ "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==",
+ "dev": true,
+ "requires": {
+ "vlq": "0.2.3"
+ }
+ },
+ "mime-db": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
+ "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==",
"dev": true
},
+ "mime-types": {
+ "version": "2.1.18",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
+ "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.33.0"
+ }
+ },
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
- "brace-expansion": "^1.1.7"
+ "brace-expansion": "1.1.11"
}
},
"minimist": {
@@ -691,9 +942,21 @@
"dev": true
},
"ms": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
- "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+ "dev": true
+ },
+ "object-component": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
+ "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
"dev": true
},
"once": {
@@ -702,7 +965,7 @@
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
- "wrappy": "1"
+ "wrappy": "1.0.2"
}
},
"optionator": {
@@ -711,12 +974,30 @@
"integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
"dev": true,
"requires": {
- "deep-is": "~0.1.3",
- "fast-levenshtein": "~2.0.4",
- "levn": "~0.3.0",
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2",
- "wordwrap": "~1.0.0"
+ "deep-is": "0.1.3",
+ "fast-levenshtein": "2.0.6",
+ "levn": "0.3.0",
+ "prelude-ls": "1.1.2",
+ "type-check": "0.3.2",
+ "wordwrap": "1.0.0"
+ }
+ },
+ "parseqs": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
+ "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
+ "dev": true,
+ "requires": {
+ "better-assert": "1.0.2"
+ }
+ },
+ "parseuri": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
+ "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
+ "dev": true,
+ "requires": {
+ "better-assert": "1.0.2"
}
},
"path-is-absolute": {
@@ -725,48 +1006,87 @@
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+ "dev": true
+ },
"path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"dev": true
},
+ "path-to-regexp": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz",
+ "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==",
+ "dev": true
+ },
+ "pixelmatch": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.0.2.tgz",
+ "integrity": "sha512-b65UpTI40rGFY8QwN6IYuCbpmwAOL6M8d6voX4F3zR99UmDqh7r2QWLxoeHOazBRgEmDUdqNVESDREqFxQS7rQ==",
+ "dev": true,
+ "requires": {
+ "pngjs": "3.4.0"
+ }
+ },
+ "pngjs": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
+ "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==",
+ "dev": true
+ },
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
"dev": true
},
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ },
+ "range-parser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
+ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=",
+ "dev": true
+ },
"resolve": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
- "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
+ "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
"dev": true,
"requires": {
- "path-parse": "^1.0.6"
+ "path-parse": "1.0.6"
}
},
"rimraf": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
- "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
- "glob": "^7.1.3"
+ "glob": "7.1.4"
},
"dependencies": {
"glob": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
- "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
+ "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"dev": true,
"requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
+ "fs.realpath": "1.0.0",
+ "inflight": "1.0.6",
+ "inherits": "2.0.1",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
}
}
}
@@ -777,16 +1097,29 @@
"integrity": "sha512-7RqCBQ9iwsOBPkjYgoIaeUij606mSkDMExP0NT7QDI3bqkHYQHrQ83uoNIXwPcQm/vP2VbsUz3kiyZZ1qPlLTQ==",
"dev": true
},
+ "rollup-plugin-commonjs": {
+ "version": "8.4.1",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-8.4.1.tgz",
+ "integrity": "sha512-mg+WuD+jlwoo8bJtW3Mvx7Tz6TsIdMsdhuvCnDMoyjh0oxsVgsjB/N0X984RJCWwc5IIiqNVJhXeeITcc73++A==",
+ "dev": true,
+ "requires": {
+ "acorn": "5.7.3",
+ "estree-walker": "0.5.2",
+ "magic-string": "0.22.5",
+ "resolve": "1.12.0",
+ "rollup-pluginutils": "2.8.1"
+ }
+ },
"rollup-plugin-node-resolve": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-3.0.0.tgz",
"integrity": "sha1-i4l8TDAw1QASd7BRSyXSygloPuA=",
"dev": true,
"requires": {
- "browser-resolve": "^1.11.0",
- "builtin-modules": "^1.1.0",
- "is-module": "^1.0.0",
- "resolve": "^1.1.6"
+ "browser-resolve": "1.11.3",
+ "builtin-modules": "1.1.1",
+ "is-module": "1.0.0",
+ "resolve": "1.12.0"
}
},
"rollup-plugin-uglify": {
@@ -795,7 +1128,24 @@
"integrity": "sha1-Z7N60e/a+9g69MNrQMGJ7khmyWk=",
"dev": true,
"requires": {
- "uglify-js": "^3.0.9"
+ "uglify-js": "3.6.0"
+ }
+ },
+ "rollup-pluginutils": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz",
+ "integrity": "sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==",
+ "dev": true,
+ "requires": {
+ "estree-walker": "0.6.1"
+ },
+ "dependencies": {
+ "estree-walker": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
+ "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
+ "dev": true
+ }
}
},
"safe-buffer": {
@@ -804,12 +1154,127 @@
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true
},
+ "seedrandom": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.3.tgz",
+ "integrity": "sha512-PJLhhxIMjlMJaiIRtqiVW061EZn3cS+waZkbFe7eCa2R3g88HbNdWmw4NTFG1w5unxd0GeNaUUxZJP7gPAzSDQ==",
+ "dev": true
+ },
"semver": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
- "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
},
+ "serve-handler": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.1.tgz",
+ "integrity": "sha512-LQPvxGia2TYqyMkHKH4jW9jx6jlQUMcWz6gJavZ3+4vsnB+SaWbYTncb9YsK5YBR6SlvyumREZJAzLw8VaFAUQ==",
+ "dev": true,
+ "requires": {
+ "bytes": "3.0.0",
+ "content-disposition": "0.5.2",
+ "fast-url-parser": "1.1.3",
+ "mime-types": "2.1.18",
+ "minimatch": "3.0.4",
+ "path-is-inside": "1.0.2",
+ "path-to-regexp": "2.2.1",
+ "range-parser": "1.2.0"
+ }
+ },
+ "slugify": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.4.tgz",
+ "integrity": "sha512-KP0ZYk5hJNBS8/eIjGkFDCzGQIoZ1mnfQRYS5WM3273z+fxGWXeN0fkwf2ebEweydv9tioZIHGZKoF21U07/nw==",
+ "dev": true
+ },
+ "socket.io": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.2.0.tgz",
+ "integrity": "sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w==",
+ "dev": true,
+ "requires": {
+ "debug": "4.1.1",
+ "engine.io": "3.3.2",
+ "has-binary2": "1.0.3",
+ "socket.io-adapter": "1.1.1",
+ "socket.io-client": "2.2.0",
+ "socket.io-parser": "3.3.0"
+ }
+ },
+ "socket.io-adapter": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz",
+ "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=",
+ "dev": true
+ },
+ "socket.io-client": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.2.0.tgz",
+ "integrity": "sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA==",
+ "dev": true,
+ "requires": {
+ "backo2": "1.0.2",
+ "base64-arraybuffer": "0.1.5",
+ "component-bind": "1.0.0",
+ "component-emitter": "1.2.1",
+ "debug": "3.1.0",
+ "engine.io-client": "3.3.2",
+ "has-binary2": "1.0.3",
+ "has-cors": "1.1.0",
+ "indexof": "0.0.1",
+ "object-component": "0.0.3",
+ "parseqs": "0.0.5",
+ "parseuri": "0.0.5",
+ "socket.io-parser": "3.3.0",
+ "to-array": "0.1.4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
+ "socket.io-parser": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz",
+ "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==",
+ "dev": true,
+ "requires": {
+ "component-emitter": "1.2.1",
+ "debug": "3.1.0",
+ "isarray": "2.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ }
+ }
+ },
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -822,9 +1287,15 @@
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
- "has-flag": "^3.0.0"
+ "has-flag": "3.0.0"
}
},
+ "to-array": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
+ "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=",
+ "dev": true
+ },
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -843,23 +1314,23 @@
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"dev": true,
"requires": {
- "prelude-ls": "~1.1.2"
+ "prelude-ls": "1.1.2"
}
},
"uglify-js": {
- "version": "3.4.9",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
- "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz",
+ "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==",
"dev": true,
"requires": {
- "commander": "~2.17.1",
- "source-map": "~0.6.1"
+ "commander": "2.20.0",
+ "source-map": "0.6.1"
},
"dependencies": {
"commander": {
- "version": "2.17.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
- "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
+ "version": "2.20.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
+ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
"dev": true
},
"source-map": {
@@ -879,6 +1350,12 @@
"inherits": "2.0.1"
}
},
+ "vlq": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
+ "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==",
+ "dev": true
+ },
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
@@ -891,480 +1368,31 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
+ "ws": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
+ "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
+ "dev": true,
+ "requires": {
+ "async-limiter": "1.0.1"
+ }
+ },
+ "xmlhttprequest-ssl": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
+ "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=",
+ "dev": true
+ },
+ "yeast": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
+ "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
+ "dev": true
+ },
"zrender": {
"version": "4.0.7",
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.0.0",
- "bundled": true,
- "requires": {
- "@babel/highlight": "^7.0.0"
- }
- },
- "@babel/core": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/generator": "^7.3.4",
- "@babel/helpers": "^7.2.0",
- "@babel/parser": "^7.3.4",
- "@babel/template": "^7.2.2",
- "@babel/traverse": "^7.3.4",
- "@babel/types": "^7.3.4",
- "convert-source-map": "^1.1.0",
- "debug": "^4.1.0",
- "json5": "^2.1.0",
- "lodash": "^4.17.11",
- "resolve": "^1.3.2",
- "semver": "^5.4.1",
- "source-map": "^0.5.0"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "bundled": true
- }
- }
- },
- "@babel/generator": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "@babel/types": "^7.3.4",
- "jsesc": "^2.5.1",
- "lodash": "^4.17.11",
- "source-map": "^0.5.0",
- "trim-right": "^1.0.1"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "bundled": true
- }
- }
- },
- "@babel/helper-function-name": {
- "version": "7.1.0",
- "bundled": true,
- "requires": {
- "@babel/helper-get-function-arity": "^7.0.0",
- "@babel/template": "^7.1.0",
- "@babel/types": "^7.0.0"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.0.0",
- "bundled": true,
- "requires": {
- "@babel/types": "^7.0.0"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.0.0",
- "bundled": true,
- "requires": {
- "@babel/types": "^7.0.0"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.2.2",
- "bundled": true,
- "requires": {
- "@babel/helper-module-imports": "^7.0.0",
- "@babel/helper-simple-access": "^7.1.0",
- "@babel/helper-split-export-declaration": "^7.0.0",
- "@babel/template": "^7.2.2",
- "@babel/types": "^7.2.2",
- "lodash": "^4.17.10"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.1.0",
- "bundled": true,
- "requires": {
- "@babel/template": "^7.1.0",
- "@babel/types": "^7.0.0"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.0.0",
- "bundled": true,
- "requires": {
- "@babel/types": "^7.0.0"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helpers": {
- "version": "7.3.1",
- "bundled": true,
- "requires": {
- "@babel/template": "^7.1.2",
- "@babel/traverse": "^7.1.5",
- "@babel/types": "^7.3.0"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/highlight": {
- "version": "7.0.0",
- "bundled": true,
- "requires": {
- "chalk": "^2.0.0",
- "esutils": "^2.0.2",
- "js-tokens": "^4.0.0"
- }
- },
- "@babel/parser": {
- "version": "7.3.4",
- "bundled": true
- },
- "@babel/template": {
- "version": "7.2.2",
- "bundled": true,
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/parser": "^7.2.2",
- "@babel/types": "^7.2.2"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/traverse": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/generator": "^7.3.4",
- "@babel/helper-function-name": "^7.1.0",
- "@babel/helper-split-export-declaration": "^7.0.0",
- "@babel/parser": "^7.3.4",
- "@babel/types": "^7.3.4",
- "debug": "^4.1.0",
- "globals": "^11.1.0",
- "lodash": "^4.17.11"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.3.4",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.17.11",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/types": {
- "version": "7.0.0-beta.31",
- "bundled": true,
- "requires": {
- "esutils": "^2.0.2",
- "lodash": "^4.2.0",
- "to-fast-properties": "^2.0.0"
- }
- },
- "ansi-styles": {
- "version": "3.2.1",
- "bundled": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "assert": {
- "version": "1.4.1",
- "bundled": true,
- "requires": {
- "util": "0.10.3"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "bundled": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "bundled": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "bundled": true
- },
- "commander": {
- "version": "2.11.0",
- "bundled": true
- },
- "convert-source-map": {
- "version": "1.6.0",
- "bundled": true,
- "requires": {
- "safe-buffer": "~5.1.1"
- }
- },
- "debug": {
- "version": "4.1.1",
- "bundled": true,
- "requires": {
- "ms": "^2.1.1"
- }
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "bundled": true
- },
- "esutils": {
- "version": "2.0.2",
- "bundled": true
- },
- "fs-extra": {
- "version": "4.0.2",
- "bundled": true,
- "requires": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- }
- },
- "globals": {
- "version": "11.11.0",
- "bundled": true
- },
- "graceful-fs": {
- "version": "4.1.11",
- "bundled": true
- },
- "has-flag": {
- "version": "3.0.0",
- "bundled": true
- },
- "inherits": {
- "version": "2.0.1",
- "bundled": true
- },
- "is-equal": {
- "version": "0.1.0",
- "bundled": true
- },
- "js-tokens": {
- "version": "4.0.0",
- "bundled": true
- },
- "jsdiff": {
- "version": "1.1.1",
- "bundled": true,
- "requires": {
- "is-equal": "~0.1.0"
- }
- },
- "jsesc": {
- "version": "2.5.2",
- "bundled": true
- },
- "json5": {
- "version": "2.1.0",
- "bundled": true,
- "requires": {
- "minimist": "^1.2.0"
- }
- },
- "jsonfile": {
- "version": "4.0.0",
- "bundled": true,
- "requires": {
- "graceful-fs": "^4.1.6"
- }
- },
- "lodash": {
- "version": "4.17.11",
- "bundled": true
- },
- "minimist": {
- "version": "1.2.0",
- "bundled": true
- },
- "ms": {
- "version": "2.1.1",
- "bundled": true
- },
- "path-parse": {
- "version": "1.0.6",
- "bundled": true
- },
- "resolve": {
- "version": "1.10.0",
- "bundled": true,
- "requires": {
- "path-parse": "^1.0.6"
- }
- },
- "rollup": {
- "version": "0.50.0",
- "bundled": true
- },
- "rollup-plugin-uglify": {
- "version": "2.0.1",
- "bundled": true,
- "requires": {
- "uglify-js": "^3.0.9"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "bundled": true
- },
- "semver": {
- "version": "5.6.0",
- "bundled": true
- },
- "source-map": {
- "version": "0.6.1",
- "bundled": true
- },
- "supports-color": {
- "version": "5.5.0",
- "bundled": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "to-fast-properties": {
- "version": "2.0.0",
- "bundled": true
- },
- "trim-right": {
- "version": "1.0.1",
- "bundled": true
- },
- "uglify-js": {
- "version": "3.1.6",
- "bundled": true,
- "requires": {
- "commander": "~2.11.0",
- "source-map": "~0.6.1"
- }
- },
- "universalify": {
- "version": "0.1.1",
- "bundled": true
- },
- "util": {
- "version": "0.10.3",
- "bundled": true,
- "requires": {
- "inherits": "2.0.1"
- }
- }
- }
+ "resolved": "https://registry.npmjs.org/zrender/-/zrender-4.0.7.tgz",
+ "integrity": "sha512-TNloHe0ums6zxbHfnaCryM61J4IWDajZwNq6dHk9vfWhhysO/OeFvvR0drBs/nbXha2YxSzfQj2FiCd6RVBe+Q=="
}
}
}
diff --git a/package.json b/package.json
index 18ad5a2..16fde6c 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
},
"scripts": {
"prepublish": "node build/build.js --prepublish",
+ "test:visual": "node test/runTest/server.js",
"test": "node build/build.js"
},
"dependencies": {
@@ -33,8 +34,16 @@
"estraverse": "4.1.1",
"fs-extra": "0.26.7",
"glob": "7.0.0",
+ "lolex": "^4.2.0",
+ "pixelmatch": "^5.0.2",
+ "pngjs": "^3.4.0",
"rollup": "0.50.0",
+ "rollup-plugin-commonjs": "^8.4.1",
"rollup-plugin-node-resolve": "3.0.0",
- "rollup-plugin-uglify": "2.0.1"
+ "rollup-plugin-uglify": "2.0.1",
+ "seedrandom": "^3.0.3",
+ "serve-handler": "^6.1.1",
+ "slugify": "^1.3.4",
+ "socket.io": "^2.2.0"
}
}
diff --git a/test/runTest/blacklist.js b/test/runTest/blacklist.js
new file mode 100644
index 0000000..9e9ad44
--- /dev/null
+++ b/test/runTest/blacklist.js
@@ -0,0 +1,4 @@
+module.exports = [
+ '-cases.html',
+ 'geo-random-stream.html'
+];
diff --git a/test/runTest/cli.js b/test/runTest/cli.js
new file mode 100644
index 0000000..e44ebe7
--- /dev/null
+++ b/test/runTest/cli.js
@@ -0,0 +1,271 @@
+const puppeteer = require('puppeteer');
+const slugify = require('slugify');
+const fse = require('fs-extra');
+const fs = require('fs');
+const path = require('path');
+const compareScreenshot = require('./compareScreenshot');
+const {getTestName, getVersionDir, buildRuntimeCode} = require('./util');
+const {origin} = require('./config');
+
+function getScreenshotDir() {
+ return 'tmp/__screenshot__';
+}
+
+function sortScreenshots(list) {
+ return list.sort((a, b) => {
+ return a.testName.localeCompare(b.testName);
+ });
+}
+
+function getClientRelativePath(absPath) {
+ return path.join('../', path.relative(__dirname, absPath));
+}
+
+function replaceEChartsVersion(interceptedRequest, version) {
+ // TODO Extensions and maps
+ if (interceptedRequest.url().endsWith('dist/echarts.js')) {
+ interceptedRequest.continue({
+ url: `${origin}/test/runTest/${getVersionDir(version)}/echarts.js`
+ });
+ }
+ else {
+ interceptedRequest.continue();
+ }
+}
+
+function waitPageForFinish(page) {
+ return new Promise(resolve => {
+ page.exposeFunction('puppeteerFinishTest', () => {
+ resolve();
+ });
+ });
+}
+
+function createWaitTimeout(maxTime) {
+ let timeoutHandle;
+ let resolve;
+ function keepWait(newMaxTime) {
+ newMaxTime = newMaxTime == null ? maxTime : newMaxTime;
+ clearTimeout(timeoutHandle);
+ createTimeout(newMaxTime);
+ }
+
+ function createTimeout(maxTime) {
+ timeoutHandle = setTimeout(() => {
+ resolve();
+ }, maxTime);
+ }
+
+ function waitTimeout() {
+ return new Promise(_resolve => {
+ resolve = _resolve;
+ createTimeout(maxTime);
+ });
+ }
+
+ return {keepWait, waitTimeout};
+}
+
+async function takeScreenshot(page, elementQuery, fileUrl, desc, version) {
+ let target = elementQuery ? await page.$(elementQuery) : page;
+ if (!target) {
+ console.error(`Can't find element '${elementQuery}'`);
+ return;
+ }
+ let fullPage = !elementQuery;
+ let testName = getTestName(fileUrl);
+ if (desc) {
+ testName += '-' + slugify(desc, { replacement: '-', lower: true })
+ }
+ let screenshotPrefix = version ? 'expected' : 'actual';
+ fse.ensureDirSync(path.join(__dirname, getScreenshotDir()));
+ let screenshotPath = path.join(__dirname, `${getScreenshotDir()}/${testName}-${screenshotPrefix}.png`);
+ await target.screenshot({
+ path: screenshotPath,
+ fullPage
+ });
+
+ return {testName, screenshotPath};
+}
+
+async function runTestPage(browser, fileUrl, version, runtimeCode) {
+ const {keepWait, waitTimeout} = createWaitTimeout(1500);
+ const screenshots = [];
+ const logs = [];
+ const errors = [];
+ let screenshotPromises = [];
+
+ const page = await browser.newPage();
+ page.setRequestInterception(true);
+ page.on('request', replaceEChartsVersion);
+ await page.evaluateOnNewDocument(runtimeCode);
+
+ let descAutoCounter = 0;
+
+ page.exposeFunction('puppeteerScreenshot', (desc, elementQuery) => {
+ keepWait();
+ desc = desc || (descAutoCounter++).toString();
+ let promise = takeScreenshot(page, elementQuery, fileUrl, desc, version).then((result) => {
+ if (!result) {
+ return;
+ }
+ const {testName, screenshotPath} = result;
+ screenshots.push({testName, desc, screenshotPath});
+ });
+ screenshotPromises.push(promise);
+
+ return promise;
+ });
+ page.on('console', msg => {
+ logs.push(msg.text());
+ });
+ page.on('pageerror', error => {
+ errors.push(error);
+ });
+
+ let pageFinishPromise = waitPageForFinish(page);
+
+ try {
+ await page.setViewport({
+ width: 800,
+ height: 600
+ });
+ await page.goto(`${origin}/test/${fileUrl}`, {
+ waitUntil: 'networkidle2',
+ // waitUntil: 'domcontentloaded',
+ timeout: 10000
+ });
+ }
+ catch(e) {
+ // TODO Timeout Error
+ console.error(e);
+ }
+
+ // TODO Animation
+
+ // Do auto screenshot after 100ms for animation.
+ // let autoSnapshotTimeout = setTimeout(async () => {
+ // let desc = `Animation Interval`;
+ // let promise = takeScreenshot(page, '', fileUrl, desc, version)
+ // .then(({testName, screenshotPath}) => {
+ // screenshots.push({testName, desc, screenshotPath});
+ // });
+ // screenshotPromises.push(promise);
+ // }, 100);
+
+ // Wait for puppeteerFinishTest() is called
+ // Or compare the whole page if nothing happened after 10 seconds.
+ await Promise.race([
+ pageFinishPromise,
+ waitTimeout().then(() => {
+ // console.warn('Test timeout after 3 seconds.');
+ // Final shot.
+ let desc = 'Final Shot';
+ return takeScreenshot(page, '', fileUrl, desc, version)
+ .then(({testName, screenshotPath}) => {
+ screenshots.push({testName, desc, screenshotPath});
+ });
+ })
+ ]);
+
+ // clearTimeout(autoSnapshotTimeout);
+
+ // Wait for screenshot finished.
+ await Promise.all(screenshotPromises);
+
+ await page.close();
+
+ return {
+ logs,
+ errors,
+ screenshots: screenshots
+ };
+}
+
+async function writePNG(diffPNG, diffPath) {
+ return new Promise(resolve => {
+ let writer = fs.createWriteStream(diffPath);
+ diffPNG.pack().pipe(writer);
+ writer.on('finish', () => {resolve();});
+ });
+};
+
+async function runTest(browser, testOpt, runtimeCode) {
+ testOpt.status === 'running';
+ const fileUrl = testOpt.fileUrl;
+ const expectedResult = await runTestPage(browser, fileUrl, '4.2.1', runtimeCode);
+ const actualResult = await runTestPage(browser, fileUrl, '', runtimeCode);
+
+ sortScreenshots(expectedResult.screenshots);
+ sortScreenshots(actualResult.screenshots);
+
+ const screenshots = [];
+ let idx = 0;
+ for (let shot of expectedResult.screenshots) {
+ let expected = shot;
+ let actual = actualResult.screenshots[idx++];
+ let {diffRatio, diffPNG} = await compareScreenshot(
+ expected.screenshotPath,
+ actual.screenshotPath
+ );
+
+ let diffPath = `${path.resolve(__dirname, getScreenshotDir())}/${shot.testName}-diff.png`;
+ await writePNG(diffPNG, diffPath);
+
+ screenshots.push({
+ actual: getClientRelativePath(actual.screenshotPath),
+ expected: getClientRelativePath(expected.screenshotPath),
+ diff: getClientRelativePath(diffPath),
+ name: actual.testName,
+ desc: actual.desc,
+ diffRatio
+ });
+ }
+
+ testOpt.results = screenshots;
+ testOpt.status = 'finished';
+ testOpt.actualLogs = actualResult.logs;
+ testOpt.expectedLogs = expectedResult.logs;
+ testOpt.actualErrors = actualResult.errors;
+ testOpt.expectedErrors = expectedResult.errors;
+
+}
+
+async function runTests(pendingTests) {
+ const browser = await puppeteer.launch({ headless: true });
+ // TODO Not hardcoded.
+ // let runtimeCode = fs.readFileSync(path.join(__dirname, 'tmp/testRuntime.js'), 'utf-8');
+ let runtimeCode = await buildRuntimeCode();
+
+ try {
+ for (let testOpt of pendingTests) {
+ console.log('Running Test', testOpt.name);
+ try {
+ await runTest(browser, testOpt, runtimeCode);
+ }
+ catch (e) {
+ // Restore status
+ testOpt.status = 'pending';
+ console.log(e);
+ }
+
+ process.send(testOpt);
+ }
+ }
+ catch(e) {
+ console.log(e);
+ }
+
+ await browser.close();
+}
+
+// Handling input arguments.
+const testsFileUrlList = process.argv[2] || '';
+runTests(testsFileUrlList.split(',').map(fileUrl => {
+ return {
+ fileUrl,
+ name: getTestName(fileUrl),
+ results: [],
+ status: 'unsettled'
+ };
+}));
\ No newline at end of file
diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css
new file mode 100644
index 0000000..cfaad1a
--- /dev/null
+++ b/test/runTest/client/client.css
@@ -0,0 +1,163 @@
+#main {
+ position: absolute;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+}
+
+* {
+ font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
+}
+
+.header {
+ background-color: #293c55;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
+ position: relative;
+ z-index: 10;
+}
+
+.header h1 {
+ color: #fff;
+ line-height: 50px;
+ margin: 0;
+ font-weight: 200;
+ font-size: 20px;
+}
+
+#logo>* {
+ display: inline-block;
+ vertical-align: middle;
+}
+
+#logo img {
+ height: 30px;
+ margin-right: 20px;
+}
+
+.nav-toolbar {
+ padding: 10px 10px;
+ background: #162436;
+ box-shadow: inset 0 0 5px black;
+ position: fixed;
+ top: 50px;
+ width: 280px;
+ z-index: 2;
+}
+.nav-toolbar .controls {
+ margin-top: 10px;
+}
+
+.test-list {
+ overflow-x: hidden;
+ background: #293c55;
+ margin: 0;
+ padding: 0;
+ margin-top: 80px;
+}
+.test-list li {
+ list-style: none;
+ padding-left: 10px;
+ cursor: pointer;
+ color: #f3f3f3;
+}
+.test-list li a.menu-link {
+ display: inline-block;
+ text-decoration: none;
+ font-size: 14px;
+ line-height: 40px;
+ color: #f3f3f3;
+ margin-left: 3px;
+ cursor: pointer;
+}
+
+.test-list li.active {
+ background: #e43c59;
+}
+.test-list li:hover {
+ background: #162436;
+}
+.test-list li>* {
+ vertical-align: middle;
+ display: inline-block
+}
+
+.test-list .el-progress__text {
+ font-size: 12px!important;
+}
+
+.test-result h3 {
+ font-size: 40px;
+ font-weight: 200;
+ padding: 0;
+ margin: 0;
+}
+
+.test-result .title>* {
+ display: inline-block;
+ vertical-align: middle;
+}
+.test-result .title a {
+ margin-left: 10px;
+ font-size: 20px;
+ font-weight: 200;
+ text-decoration: none;
+}
+.test-result .title a:hover {
+ text-decoration: underline;
+}
+
+.test-screenshots {
+ margin-top: 80px;
+ padding: 0 20px;
+}
+
+.test-screenshots img {
+ /* height: 200px; */
+ width: 100%;
+}
+.test-screenshots h4 {
+ font-size: 30px;
+ font-weight: 200;
+ margin-left: -20px;
+ color: #162436;
+}
+
+.test-errors, .test-logs {
+ margin-top: 20px;
+ padding: 0 50px;
+}
+
+.test-logs .log-item {
+ margin: 10px 20px;
+ color: #909399;
+}
+
+.test-errors .error-item {
+ margin: 10px 20px;
+ color: #f56c6c
+}
+
+
+::-webkit-scrollbar {
+ height:8px;
+ width:8px;
+ transition:all 0.3s ease-in-out;
+ border-radius:2px;
+ background: transparent;
+}
+
+::-webkit-scrollbar-button {
+ display:none;
+}
+
+::-webkit-scrollbar-thumb {
+ width:8px;
+ min-height:15px;
+ background:rgba(50, 50, 50, 0.6) !important;
+ transition:all 0.3s ease-in-out;border-radius:2px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background:rgba(0, 0, 0, 0.5) !important;
+}
\ No newline at end of file
diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js
new file mode 100644
index 0000000..0dc2607
--- /dev/null
+++ b/test/runTest/client/client.js
@@ -0,0 +1,182 @@
+const socket = io();
+
+function processTestsData(tests, oldTestsData) {
+ tests.forEach((test, idx) => {
+ let passed = 0;
+ test.index = idx;
+ test.results.forEach(result => {
+ // Threshold?
+ if (result.diffRatio < 0.001) {
+ passed++;
+ }
+ });
+ test.percentage = passed === 0 ? 0 : Math.round(passed / test.results.length * 100);
+ if (test.percentage === 100) {
+ test.summary = 'success';
+ }
+ else if (test.percentage < 50) {
+ test.summary = 'exception';
+ }
+ else {
+ test.summary = 'warning';
+ }
+
+ // Keep select status not change.
+ if (oldTestsData && oldTestsData[idx]) {
+ test.selected = oldTestsData[idx].selected;
+ }
+ else {
+ test.selected = false;
+ }
+ });
+ return tests;
+}
+
+socket.on('connect', () => {
+ console.log('Connected');
+ const app = new Vue({
+ el: '#app',
+ data: {
+ fullTests: [],
+ currentTestName: '',
+ sortBy: 'name',
+ searchString: '',
+ running: false,
+
+ allSelected: false,
+ lastSelectedIndex: -1
+ },
+ computed: {
+ tests() {
+ let sortFunc = this.sortBy === 'name'
+ ? (a, b) => a.name.localeCompare(b.name)
+ : (a, b) => {
+ if (a.percentage === b.percentage) {
+ return a.name.localeCompare(b.name);
+ }
+ return a.percentage - b.percentage;
+ };
+
+ if (!this.searchString) {
+ // Not modify the original tests data.
+ return this.fullTests.slice().sort(sortFunc);
+ }
+
+ return this.fullTests.filter(test => {
+ return test.name.match(this.searchString);
+ }).sort(sortFunc);
+ },
+
+ currentTest() {
+ let currentTest = this.fullTests.find(item => item.name === this.currentTestName);
+ if (!currentTest) {
+ currentTest = this.fullTests[0];
+ }
+ return currentTest;
+ },
+
+ currentTestUrl() {
+ return window.location.origin + '/test/' + this.currentTest.fileUrl;
+ },
+
+ isSelectAllIndeterminate: {
+ get() {
+ if (!this.tests.length) {
+ return true;
+ }
+ return this.tests.some(test => {
+ return test.selected !== this.tests[0].selected;
+ });
+ },
+ set() {}
+ }
+ },
+ methods: {
+ goto(url) {
+ window.location.hash = '#' + url;
+ },
+ toggleSort() {
+ this.sortBy = this.sortBy === 'name' ? 'percentage' : 'name';
+ },
+ handleSelectAllChange(val) {
+ // Only select filtered tests.
+ this.tests.forEach(test => {
+ test.selected = val;
+ });
+ this.isSelectAllIndeterminate = false;
+ },
+ handleSelect(idx) {
+ Vue.nextTick(() => {
+ this.lastSelectedIndex = idx;
+ });
+ },
+ handleShiftSelect(idx) {
+ if (this.lastSelectedIndex < 0) {
+ return;
+ }
+ let start = Math.min(this.lastSelectedIndex, idx);
+ let end = Math.max(this.lastSelectedIndex, idx);
+ let selected = !this.tests[idx].selected; // Will change
+ for (let i = start; i < end; i++) {
+ this.tests[i].selected = selected;
+ }
+ },
+ refreshList() {
+
+ },
+ runSelectedTests() {
+ const tests = this.fullTests.filter(test => {
+ return test.selected;
+ }).map(test => {
+ return test.name;
+ });
+ if (tests.length > 0) {
+ this.running = true;
+ socket.emit('run', tests);
+ }
+ },
+ stopTests() {
+ this.running = false;
+ socket.emit('stop');
+ }
+ }
+ });
+ app.$el.style.display = 'block';
+
+ let firstUpdate = true;
+ socket.on('update', msg => {
+ let hasFinishedTest = !!msg.tests.find(test => test.status === 'finished');
+ if (!hasFinishedTest && firstUpdate) {
+ app.$confirm('It seems you haven\'t run any test yet!<br />Do you want to start now?', 'Tip', {
+ confirmButtonText: 'Yes',
+ cancelButtonText: 'No',
+ dangerouslyUseHTMLString: true,
+ center: true
+ }).then(value => {
+ app.running = true;
+ socket.emit('run', msg.tests.map(test => test.name));
+ }).catch(() => {});
+ }
+ // TODO
+ // app.running = !!msg.running;
+ app.fullTests = processTestsData(msg.tests, app.fullTests);
+
+ firstUpdate = false;
+ });
+ socket.on('finish', () => {
+ app.$notify({
+ title: 'Test Complete',
+ position: 'bottom-right'
+ });
+ app.running = false;
+ });
+
+ function updateTestHash() {
+ let testName = window.location.hash.slice(1);
+ app.currentTestName = testName;
+ }
+
+ updateTestHash();
+ window.addEventListener('hashchange', updateTestHash);
+});
+
diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html
new file mode 100644
index 0000000..c45b49d
--- /dev/null
+++ b/test/runTest/client/index.html
@@ -0,0 +1,168 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+</head>
+<body>
+<div id="app" style="display: none">
+ <el-container id="main">
+ <el-header class="header" height="50">
+ <div id="logo">
+ <img src="https://echarts.apache.org/zh/images/logo.png" />
+ <h1>Visual Regression Test</h1>
+ </div>
+ </el-header>
+ <el-container style="min-height: 0"> <!-- https://juejin.im/post/5c642f2ff265da2de660ecfc -->
+ <el-aside width="300px">
+ <div class="nav-toolbar">
+ <el-input v-model="searchString" size="mini" placeholder="Filter Tests"></el-input>
+ <div class="controls">
+ <el-checkbox :indeterminate="isSelectAllIndeterminate" v-model="allSelected" @change="handleSelectAllChange"></el-checkbox>
+ <el-button-group>
+ <el-button title="Run Selected" @click="runSelectedTests" :loading="running" circle size="mini" type="primary" icon="el-icon-caret-right"></el-button>
+ <el-button v-if="running" title="Run Selected" @click="stopTests" circle size="mini" type="primary" icon="el-icon-close"></el-button>
+ </el-button-group>
+
+ <el-button
+ style="margin-left: 10px"
+ title="Sort By Failue Percentage" @click="toggleSort" circle size="mini" type="primary" icon="el-icon-sort"
+ ></el-button>
+ <!-- <el-button-group>
+ <el-button title="Select All" @click="selectAllTests" circle size="mini" type="primary" icon="el-icon-check"></el-button>
+ <el-button title="Unselect All" @click="unselectAllTests" circle size="mini" type="primary" icon="el-icon-close"></el-button>
+ </el-button-group> -->
+ <!-- <el-button title="Refresh List" @click="refreshList" circle size="mini" type="primary" icon="el-icon-refresh"></el-button> -->
+ </div>
+ </div>
+ <ul class="test-list">
+ <li v-for="(test, index) in tests"
+ :title="test.name"
+ :class="{active: currentTest && currentTest.name === test.name}"
+ @click.self="goto(test.name)"
+ >
+ <span @mouseup="handleSelect(index)" @mouseup.shift="handleShiftSelect(index)">
+ <el-checkbox v-model="test.selected"></el-checkbox>
+ </span>
+ <i class="el-icon-loading" v-if="test.status === 'pending' && running"></i>
+ <el-progress
+ v-if="test.status === 'finished'"
+ type="circle"
+ :width="20"
+ :stroke-width="2"
+ :percentage="test.percentage"
+ :status="test.summary"
+ ></el-progress>
+ <a :href="'#' + test.name" class="menu-link">{{test.name}}</a>
+
+ </li>
+ </ul>
+ </el-aside>
+ <el-main>
+ <div v-if="currentTest" class="test-result">
+ <div class="title">
+ <h3>{{currentTest.name}}</h3>
+ <a target="_blank" :href="currentTestUrl"><i class="el-icon-link"></i>Open Demo</a>
+ </div>
+
+ <div class="test-screenshots" v-for="result in currentTest.results">
+ <h4>{{result.desc || result.name}}</h4>
+ <el-row :gutter="40" class="screenshots">
+ <el-col :span="8">
+ <el-card>
+ <div slot="header" class="clearfix">
+ <span>Expected</span>
+ </div>
+ <el-image :src="result.expected" :preview-src-list="[result.expected]"></el-image>
+ </el-card>
+ </el-col>
+
+ <el-col :span="8">
+ <el-card>
+ <div slot="header" class="clearfix">
+ <span>Actual</span>
+ </div>
+ <el-image :src="result.actual" :preview-src-list="[result.actual]"></el-image>
+ </el-card>
+ </el-col>
+
+ <el-col :span="8">
+ <el-card>
+ <div slot="header" class="clearfix">
+ <span>Diff({{result.diffRatio.toFixed(4)}})</span>
+ </div>
+ <el-image :src="result.diff" :preview-src-list="[result.diff]"></el-image>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+
+ <div class="test-errors">
+ <el-row :gutter="40">
+ <el-col :span="12">
+ <el-alert
+ title="Expected Errors"
+ type="error"
+ show-icon>
+ </el-alert>
+ <div class="error-item" v-for="error in currentTest.expectedErrors">{{error}}</div>
+ </el-col>
+ <el-col :span="12">
+ <el-alert
+ title="Actual Errors"
+ type="error"
+ show-icon>
+ </el-alert>
+ <div class="error-item" v-for="error in currentTest.actualErrors">{{error}}</div>
+ </el-col>
+ </el-row>
+ </div>
+
+ <div class="test-logs">
+ <el-row :gutter="40">
+ <el-col :span="12">
+ <el-alert
+ title="Expected Logs"
+ type="info"
+ show-icon>
+ </el-alert>
+ <div class="log-item" v-for="log in currentTest.expectedLogs">{{log}}</div>
+ </el-col>
+ <el-col :span="12">
+ <el-alert
+ title="Actual Logs"
+ type="info"
+ show-icon>
+ </el-alert>
+ <div class="log-item" v-for="log in currentTest.actualLogs">{{log}}</div>
+ </el-col>
+ </el-row>
+ </div>
+
+ <div class="test-result-nav">
+
+ </div>
+ </div>
+ </el-main>
+ </el-container>
+ </el-container>
+
+
+
+</div>
+
+<script src="../../../node_modules/socket.io-client/dist/socket.io.js"></script>
+<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
+
+<!-- Element UI -->
+<link rel="stylesheet" href="https://unpkg.com/element-ui@2.11.1/lib/theme-chalk/index.css">
+<script src="https://unpkg.com/element-ui@2.11.1/lib/index.js"></script>
+
+<script src="client.js"></script>
+
+<link rel="stylesheet" href="client.css">
+<link rel="stylesheet" href="">
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test/runTest/compareScreenshot.js b/test/runTest/compareScreenshot.js
new file mode 100644
index 0000000..8fd36c8
--- /dev/null
+++ b/test/runTest/compareScreenshot.js
@@ -0,0 +1,41 @@
+const PNG = require('pngjs').PNG;
+const pixelmatch = require('pixelmatch');
+const fs = require('fs');
+
+function readPNG(path) {
+ return new Promise(resolve => {
+ fs.createReadStream(path)
+ .pipe(new PNG())
+ .on('parsed', function () {
+ resolve({
+ data: this.data,
+ width: this.width,
+ height: this.height
+ });
+ });
+ });
+}
+
+module.exports = function (expectedShotPath, actualShotPath, threshold = 0.1) {
+ return Promise.all([
+ readPNG(expectedShotPath),
+ readPNG(actualShotPath)
+ ]).then(([expectedImg, actualImg]) => {
+ let width = expectedImg.width;
+ let height = expectedImg.height;
+ if (
+ (width !== actualImg.width)
+ || (height !== actualImg.height)
+ ) {
+ throw new Error('Image size not match');
+ }
+ const diffPNG = new PNG({width, height});
+ let diffPixelsCount = pixelmatch(expectedImg.data, actualImg.data, diffPNG.data, width, height, {threshold});
+ let totalPixelsCount = width * height;
+
+ return {
+ diffRatio: diffPixelsCount / totalPixelsCount,
+ diffPNG
+ };
+ });
+};
diff --git a/test/runTest/config.js b/test/runTest/config.js
new file mode 100644
index 0000000..7234965
--- /dev/null
+++ b/test/runTest/config.js
@@ -0,0 +1,4 @@
+module.exports = {
+ port: 8866,
+ origin: 'http://localhost:8866'
+};
\ No newline at end of file
diff --git a/test/runTest/runtime/main.js b/test/runTest/runtime/main.js
new file mode 100644
index 0000000..35da2f1
--- /dev/null
+++ b/test/runTest/runtime/main.js
@@ -0,0 +1,53 @@
+import seedrandom from 'seedrandom';
+import lolex from 'lolex';
+
+// const NativeDate = window.Date;
+
+// const fixedTimestamp = 1566458693300;
+// const actualTimestamp = NativeDate.now();
+// function MockDate(params) {
+// if (!params) {
+// const elapsedTime = NativeDate.now() - actualTimestamp;
+// return new NativeDate(fixedTimestamp + elapsedTime);
+// }
+// else {
+// return new NativeDate(params);
+// }
+// }
+// MockDate.prototype = new Date();
+// // Fixed date
+// window.Date = MockDate;
+
+// export function createScreenshotTest (desc, elementQuery, waitTime) {
+
+// };
+
+/**
+ * Take screenshot immediately.
+ * @param {string} desc
+ * @param {string} [elementQuery] If only screenshot specifed element. Will do full page screenshot if it's not give.
+ */
+export function compareScreenshot (desc, elementQuery) {
+ return puppeteerScreenshot(desc, elementQuery);
+};
+
+/**
+ * Finish the test.
+ */
+export function finish() {
+ return puppeteerFinishTest();
+};
+
+
+let myRandom = new seedrandom('echarts-test');
+// Fixed random generator
+Math.random = function () {
+ const val = myRandom();
+ return val;
+};
+
+// lolex.install({
+// shouldAdvanceTime: true,
+// advanceTimeDelta: 200,
+// now: fixedTimestamp
+// });
diff --git a/test/runTest/runtime/shim.js b/test/runTest/runtime/shim.js
new file mode 100644
index 0000000..d0febb4
--- /dev/null
+++ b/test/runTest/runtime/shim.js
@@ -0,0 +1,9 @@
+(function () {
+ if (typeof autorun !== 'undefined') {
+ return;
+ }
+ var autorun = {};
+ autorun.createScreenshotTest = function () {};
+ autorun.compareScreenshot = function () {};
+ autorun.finish = function () {};
+})();
\ No newline at end of file
diff --git a/test/runTest/server.js b/test/runTest/server.js
new file mode 100644
index 0000000..8900f94
--- /dev/null
+++ b/test/runTest/server.js
@@ -0,0 +1,127 @@
+const handler = require('serve-handler');
+const http = require('http');
+const path = require('path');
+// const open = require('open');
+const fse = require('fs-extra');
+const {fork} = require('child_process');
+const {port, origin} = require('./config');
+const {getTestsList, prepareTestsList, saveTestsList, mergeTestsResults} = require('./store');
+const {prepareEChartsVersion, buildRuntimeCode} = require('./util');
+
+function serve() {
+ const server = http.createServer((request, response) => {
+ return handler(request, response, {
+ cleanUrls: false,
+ // Root folder of echarts
+ public: __dirname + '/../../'
+ });
+ });
+
+ server.listen(port, () => {
+ console.log(`Server started. ${origin}`);
+ });
+
+
+ const io = require('socket.io')(server);
+ return {
+ io
+ };
+};
+
+let testProcess;
+let pendingTests;
+
+function stopRunningTests() {
+ if (testProcess) {
+ testProcess.kill();
+ testProcess = null;
+ }
+ if (pendingTests) {
+ pendingTests.forEach(testOpt => {
+ if (testOpt.status === 'pending') {
+ testOpt.status = 'unsettled';
+ }
+ });
+ pendingTests = null;
+ }
+}
+
+function startTests(testsNameList, socket) {
+ console.log(testsNameList.join(','));
+
+ stopRunningTests();
+
+ return new Promise(resolve => {
+ pendingTests = getTestsList().filter(testOpt => {
+ return testsNameList.includes(testOpt.name);
+ });
+ pendingTests.forEach(testOpt => {
+ // Reset all tests results
+ testOpt.status = 'pending';
+ testOpt.results = [];
+ });
+
+ socket.emit('update', {tests: getTestsList()});
+
+ testProcess = fork(path.join(__dirname, 'cli.js'), [
+ pendingTests.map(testOpt => testOpt.fileUrl)
+ ]);
+ // Finished one test
+ testProcess.on('message', testOpt => {
+ mergeTestsResults([testOpt]);
+ // Merge tests.
+ socket.emit('update', {tests: getTestsList(), running: true});
+ saveTestsList();
+ });
+ // Finished all
+ testProcess.on('exit', () => {
+ resolve();
+ });
+ });
+}
+
+function checkPuppeteer() {
+ try {
+ return require('puppeteer');
+ }
+ catch (e) {
+ return null;
+ }
+}
+
+async function start() {
+ if (!checkPuppeteer()) {
+ // TODO Check version.
+ console.error(`Can't find puppeteer, use 'npm install puppeteer' to install`);
+ return;
+ }
+
+ await prepareEChartsVersion('4.2.1'); // Expected version.
+ await prepareEChartsVersion(); // Version to test
+
+ let runtimeCode = await buildRuntimeCode();
+ fse.outputFileSync(path.join(__dirname, 'tmp/testRuntime.js'), runtimeCode, 'utf-8');
+
+ // Start a static server for puppeteer open the html test cases.
+ let {io} = serve();
+
+ io.on('connect', async socket => {
+ await prepareTestsList();
+
+ socket.emit('update', {tests: getTestsList()});
+ // TODO Stop previous?
+ socket.on('run', async testsNameList => {
+ await startTests(testsNameList, socket);
+ socket.emit('finish');
+ });
+ socket.on('stop', () => {
+ stopRunningTests();
+ });
+ });
+
+ console.log(`Dashboard: ${origin}/test/runTest/client/index.html`);
+ // open(`${origin}/test/runTest/client/index.html`);
+
+}
+
+start();
\ No newline at end of file
diff --git a/test/runTest/store.js b/test/runTest/store.js
new file mode 100644
index 0000000..4cd4fc9
--- /dev/null
+++ b/test/runTest/store.js
@@ -0,0 +1,78 @@
+const path = require('path');
+const fse = require('fs-extra');
+const fs = require('fs');
+const glob = require('glob');
+const {getTestName} = require('./util');
+const util = require('util');
+const blacklist = require('./blacklist');
+
+let _tests = [];
+let _testsMap = {};
+
+function getCacheFilePath() {
+ return path.join(__dirname, 'tmp/__cache__.json');;
+}
+
+module.exports.getTestsList = function () {
+ return _tests;
+};
+
+module.exports.getTestByFileUrl = function (url) {
+ return _testsMap[url];
+};
+
+module.exports.prepareTestsList = async function () {
+ let tmpFolder = path.join(__dirname, 'tmp');
+ fse.ensureDirSync(tmpFolder);
+ _tests = [];
+ _testsMap = {};
+ try {
+ let cachedStr = fs.readFileSync(getCacheFilePath(), 'utf-8');
+ _tests = JSON.parse(cachedStr);
+ _tests.forEach(test => {
+ // In somehow tests are stopped and leave the status pending.
+ // Set the status to unsettled again.
+ if (test.status === 'pending') {
+ test.status = 'unsettled';
+ }
+ _testsMap[test.fileUrl] = test;
+ });
+ }
+ catch(e) {
+ _tests = [];
+ }
+ // Find if there is new html file
+ let files = await util.promisify(glob)('**.html', { cwd: path.resolve(__dirname, '../') });
+ files.forEach(fileUrl => {
+ if (blacklist.includes(fileUrl)) {
+ return;
+ }
+ if (_testsMap[fileUrl]) {
+ return;
+ }
+
+ let test = {
+ fileUrl,
+ name: getTestName(fileUrl),
+ // Default status should be unkown
+ // status: 'pending',
+ results: []
+ };
+
+ _tests.push(test);
+ _testsMap[fileUrl] = test;
+ });
+ return _tests;
+};
+
+module.exports.saveTestsList = function () {
+ fse.outputFileSync(getCacheFilePath(), JSON.stringify(_tests, null, 2), 'utf-8');
+};
+
+module.exports.mergeTestsResults = function (testsResults) {
+ testsResults.forEach(testResult => {
+ if (_testsMap[testResult.fileUrl]) {
+ Object.assign(_testsMap[testResult.fileUrl], testResult);
+ }
+ });
+};
\ No newline at end of file
diff --git a/test/runTest/util.js b/test/runTest/util.js
new file mode 100644
index 0000000..95cab47
--- /dev/null
+++ b/test/runTest/util.js
@@ -0,0 +1,66 @@
+const path = require('path');
+const fse = require('fs-extra');
+const https = require('https');
+const fs = require('fs');
+const rollup = require('rollup');
+const resolve = require('rollup-plugin-node-resolve');
+const commonjs = require('rollup-plugin-commonjs');
+
+module.exports.getTestName = function(fileUrl) {
+ return path.basename(fileUrl, '.html');
+};
+
+
+function getVersionDir(version) {
+ version = version || 'developing';
+ return `tmp/__version__/${version}`;
+};
+module.exports.getVersionDir = getVersionDir;
+
+
+module.exports.prepareEChartsVersion = function (version) {
+ let versionFolder = path.join(__dirname, getVersionDir(version));
+ fse.ensureDirSync(versionFolder);
+ if (!version) {
+ // Developing version, make sure it's new build
+ return fse.copy(
+ path.join(__dirname, '../../dist/echarts.js'),
+ `${versionFolder}/echarts.js`
+ );
+ }
+ return new Promise(resolve => {
+ if (!fs.existsSync(`${versionFolder}/echarts.js`)) {
+ const file = fs.createWriteStream(`${versionFolder}/echarts.js`);
+
+ console.log('Downloading echarts4.2.1 from ', `https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`);
+ https.get(`https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`, response => {
+ response.pipe(file);
+
+ file.on('finish', () => {
+ resolve();
+ });
+ });
+ }
+ else {
+ resolve();
+ }
+ });
+};
+
+module.exports.buildRuntimeCode = async function () {
+ const bundle = await rollup.rollup({
+ input: path.join(__dirname, 'runtime/main.js'),
+ plugins: [
+ resolve(),
+ commonjs()
+ ]
+ });
+ const output = await bundle.generate({
+ format: 'iife',
+ name: 'autorun'
+ });
+
+ // seedrandom use crypto as external module. Set it to null to avoid not defined error.
+ // TODO
+ return 'window.crypto = null\n' + output.code;
+};
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org