This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a commit to branch enhance-visual-regression-test
in repository https://gitbox.apache.org/repos/asf/echarts.git
The following commit(s) were added to refs/heads/enhance-visual-regression-test
by this push:
new c7f9a4b test(visual): add test runs manager
c7f9a4b is described below
commit c7f9a4beed50849f5e9c56f8f1bc53eb2e9ea125
Author: pissang <[email protected]>
AuthorDate: Fri Apr 30 13:49:05 2021 +0800
test(visual): add test runs manager
---
test/runTest/cli.js | 4 ++
test/runTest/client/client.css | 5 ++
test/runTest/client/client.js | 36 +++++++++++++++
test/runTest/client/index.html | 40 +++++++++++++++-
test/runTest/server.js | 36 ++++++++++-----
test/runTest/store.js | 101 +++++++++++++++++++++++++++++++++++++----
6 files changed, 199 insertions(+), 23 deletions(-)
diff --git a/test/runTest/cli.js b/test/runTest/cli.js
index f6f5ed4..59b9bf7 100644
--- a/test/runTest/cli.js
+++ b/test/runTest/cli.js
@@ -327,6 +327,10 @@ async function runTests(pendingTests) {
let runtimeCode = await buildRuntimeCode();
runtimeCode = `window.__TEST_PLAYBACK_SPEED__ = ${program.speed ||
1};\n${runtimeCode}`;
+ process.on('exit', () => {
+ browser.close();
+ });
+
try {
for (let testOpt of pendingTests) {
console.log(`Running test: ${testOpt.name}, renderer:
${program.renderer}`);
diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css
index 22d37f6..f9926ab 100644
--- a/test/runTest/client/client.css
+++ b/test/runTest/client/client.css
@@ -267,6 +267,11 @@ iframe {
overflow: overlay;
}
+#tests-runs-dialog .el-dialog {
+ width: 90%;
+ max-width: 1400px;
+}
+
::-webkit-scrollbar {
height: 8px;
diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js
index 2db45fd..a9dd0e5 100644
--- a/test/runTest/client/client.js
+++ b/test/runTest/client/client.js
@@ -109,6 +109,10 @@ const app = new Vue({
previewIframeSrc: '',
previewTitle: '',
+ // List of all runs.
+ showRunsDialog: false,
+ testsRuns: [],
+
runConfig: Object.assign({
sortBy: 'name',
@@ -336,6 +340,34 @@ const app = new Vue({
}
}
});
+ },
+
+ showAllTestsRuns() {
+ this.showRunsDialog = true;
+ socket.emit('getAllTestsRuns');
+ },
+
+ switchTestsRun(runResult) {
+
+ },
+ genTestsRunReport(runResult) {
+
+ },
+
+ delTestsRun(runResult) {
+ app.$confirm('Are you sure to delete this run?', 'Warn', {
+ confirmButtonText: 'Yes',
+ cancelButtonText: 'No',
+ center: true
+ }).then(value => {
+ const idx = this.testsRuns.indexOf(runResult);
+ if (idx >= 0) {
+ this.testsRuns.splice(idx, 1);
+ }
+ socket.emit('delTestsRun', {
+ id: runResult.id
+ });
+ }).catch(() => {});
}
}
});
@@ -415,6 +447,10 @@ socket.on('abort', res => {
app.running = false;
});
+socket.on('getAllTestsRuns_return', res => {
+ app.testsRuns = res.runs;
+});
+
function updateUrl(notRefresh) {
const searchUrl = assembleParams({
test: app.currentTestName,
diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html
index 72e6536..6205407 100644
--- a/test/runTest/client/index.html
+++ b/test/runTest/client/index.html
@@ -37,6 +37,7 @@ under the License.
</div>
</el-header>
<el-container style="min-height: 0"> <!--
https://juejin.im/post/5c642f2ff265da2de660ecfc -->
+ <!-------- Tests List ----------->
<el-aside width="350px">
<div class="nav-toolbar">
<el-row class="filters" :gutter="10" :align="'middle'">
@@ -119,6 +120,16 @@ under the License.
</el-button-group>
</div>
+ <div class="run-config-item">
+ <el-tooltip content="Show All Tests Runs">
+ <i
+ style="font-size: 20px; cursor: pointer;"
+ class="el-icon-files"
+ @click="showAllTestsRuns"
+ ></i>
+ </el-tooltip>
+ </div>
+
<!-- <div class="run-config-item">
<el-checkbox
v-model="runConfig.noHeadless">Replay</el-checkbox>
@@ -169,7 +180,7 @@ under the License.
</div>
</div>
-
+ <!-------- Single Test Reusult ----------->
<div v-if="currentTest" class="test-result">
<div class="title">
<el-progress
@@ -268,6 +279,33 @@ under the License.
</div>
<iframe :src="previewIframeSrc" width="800"
height="600"></iframe>
</el-dialog>
+
+ <!-------- All Tests Runs ----------->
+ <el-dialog
+ id="tests-runs-dialog"
+ :visible.sync="showRunsDialog"
+ title="All Tests Runs"
+ >
+ <el-table :data="testsRuns">
+ <el-table-column property="expectedVersion"
label="Expected"></el-table-column>
+ <el-table-column property="actualVersion"
label="Actual"></el-table-column>
+ <el-table-column property="renderer" label="Renderer"
width="100"></el-table-column>
+ <el-table-column property="lastRunTime"
label="lastRunTime"></el-table-column>
+ <el-table-column property="total" label="Total Tests"
width="100"></el-table-column>
+ <el-table-column property="finished" label="Finished"
width="100"></el-table-column>
+ <el-table-column property="passed" label="Passed"
width="100"></el-table-column>
+ <el-table-column
+ fixed="right"
+ label=""
+ width="160">
+ <template slot-scope="scope">
+ <el-button type="text"
@click="switchTestsRun(scope.row)" size="small">View</el-button>
+ <el-button type="text"
@click="genTestsRunReport(scope.row)" size="small">Report</el-button>
+ <el-button type="text"
@click="delTestsRun(scope.row)" size="small">Delete</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-dialog>
</el-main>
</el-container>
</el-container>
diff --git a/test/runTest/server.js b/test/runTest/server.js
index 4f78187..a73afd3 100644
--- a/test/runTest/server.js
+++ b/test/runTest/server.js
@@ -24,14 +24,22 @@ const path = require('path');
const {fork} = require('child_process');
const semver = require('semver');
const {port, origin} = require('./config');
-const {getTestsList, updateTestsList, saveTestsList, mergeTestsResults,
updateActionsMeta, getResultBaseDir} = require('./store');
+const {
+ getTestsList,
+ updateTestsList,
+ saveTestsList,
+ mergeTestsResults,
+ updateActionsMeta,
+ getResultBaseDir,
+ getRunHash,
+ getAllTestsRuns,
+ delTestsRun
+} = require('./store');
const {prepareEChartsLib, getActionsFullPath} = require('./util');
const fse = require('fs-extra');
const fs = require('fs');
const open = require('open');
-const TEST_HASH_SPLITTER = '__';
-
function serve() {
const server = http.createServer((request, response) => {
return handler(request, response, {
@@ -199,13 +207,6 @@ function checkPuppeteer() {
}
}
-function getTestHash(params) {
- return [
- params.expectedVersion,
- params.actualVersion,
- params.renderer
- ].join(TEST_HASH_SPLITTER);
-}
async function start() {
if (!checkPuppeteer()) {
@@ -234,12 +235,12 @@ async function start() {
}
socket.on('setTestVersions', async (params) => {
- if (_currentTestHash !== getTestHash(params)) {
+ if (_currentTestHash !== getRunHash(params)) {
abortTests();
}
await updateTestsList(
- _currentTestHash = getTestHash(params),
+ _currentTestHash = getRunHash(params),
!running // Set to unsettled if not running
);
@@ -249,6 +250,17 @@ async function start() {
});
});
+ socket.on('getAllTestsRuns', async () => {
+ socket.emit('getAllTestsRuns_return', {
+ runs: await getAllTestsRuns()
+ });
+ });
+
+ socket.on('delTestsRun', async (params) => {
+ delTestsRun(params.id);
+ console.log('Deleted', params.id);
+ });
+
socket.on('run', async data => {
let startTime = Date.now();
diff --git a/test/runTest/store.js b/test/runTest/store.js
index 8da5852..a6135bb 100644
--- a/test/runTest/store.js
+++ b/test/runTest/store.js
@@ -20,14 +20,18 @@
const path = require('path');
const fse = require('fs-extra');
const fs = require('fs');
-const glob = require('glob');
+const globby = require('globby');
const {testNameFromFile} = require('./util');
-const util = require('util');
const {blacklist, SVGBlacklist} = require('./blacklist');
let _tests = [];
let _testsMap = {};
-let _testHash = '';
+let _runHash = '';
+
+const RESULT_FILE_NAME = '__result__.json';
+const RESULTS_ROOT_DIR = path.join(__dirname, 'tmp', 'result');
+
+const TEST_HASH_SPLITTER = '__';
class Test {
constructor(fileUrl) {
@@ -59,14 +63,40 @@ class Test {
}
}
+
+/**
+ * hash of each run is mainly for storing the results.
+ * It depends on two versions and rendering mode.
+ */
+function getRunHash(params) {
+ return [
+ params.expectedVersion,
+ params.actualVersion,
+ params.renderer
+ ].join(TEST_HASH_SPLITTER);
+}
+
+/**
+ * Parse versions and rendering mode from run hash.
+ */
+function parseRunHash(str) {
+ const parts = str.split(TEST_HASH_SPLITTER);
+ return {
+ expectedVersion: parts[0],
+ actualVersion: parts[1],
+ renderer: parts[2]
+ };
+}
+
function getResultBaseDir() {
- return path.join(__dirname, 'tmp', 'result', _testHash);
+ return path.join(RESULTS_ROOT_DIR, _runHash);
}
module.exports.getResultBaseDir = getResultBaseDir;
+module.exports.getRunHash = getRunHash;
-function getCacheFilePath(baseDir) {
- return path.join(getResultBaseDir(), '__result__.json');;
+function getCacheFilePath() {
+ return path.join(getResultBaseDir(), RESULT_FILE_NAME);
}
module.exports.getTestsList = function () {
@@ -78,10 +108,10 @@ module.exports.getTestByFileUrl = function (url) {
};
module.exports.updateTestsList = async function (
- testHash,
+ runHash,
setPendingTestToUnsettled
) {
- _testHash = testHash;
+ _runHash = runHash;
_tests = [];
_testsMap = {};
_testsExists = {};
@@ -105,7 +135,7 @@ module.exports.updateTestsList = async function (
catch(e) {
}
// Find if there is new html file
- const files = await util.promisify(glob)('**.html', { cwd:
path.resolve(__dirname, '../') });
+ const files = await globby('**.html', { cwd: path.resolve(__dirname,
'../') });
files.forEach(fileUrl => {
if (blacklist.includes(fileUrl)) {
return;
@@ -169,4 +199,55 @@ module.exports.updateActionsMeta = function (testName,
actions) {
fs.writeFileSync(metaPath, JSON.stringify(
metaData, Object.keys(metaData).sort((a, b) => a.localeCompare(b)), 2
), 'utf-8');
-};
\ No newline at end of file
+};
+
+/**
+ * Get results of all runs
+ * @return [ { id, expectedVersion, actualVersion, renderer, lastRunTime,
total, finished, passed } ]
+ */
+module.exports.getAllTestsRuns = async function () {
+ const dirs = await globby('*', { cwd: RESULTS_ROOT_DIR, onlyDirectories:
true });
+ return dirs.map((dir) => {
+ const params = parseRunHash(dir);
+ const resultJson = JSON.parse(fs.readFileSync(path.join(
+ RESULTS_ROOT_DIR,
+ dir,
+ RESULT_FILE_NAME
+ ), 'utf-8'));
+
+ const total = resultJson.length;
+ let lastRunTime = 0;
+ let finishedCount = 0;
+ let passedCount = 0;
+
+ resultJson.forEach(test => {
+ lastRunTime = Math.max(test.lastRun, lastRunTime);
+ if (test.status === 'finished') {
+ finishedCount++;
+
+ let passed = true;
+ test.results.forEach(result => {
+ // Threshold?
+ if (result.diffRatio > 0.0001) {
+ passed = false;
+ }
+ });
+ if (passed) {
+ passedCount++;
+ }
+ }
+ });
+
+ params.lastRunTime = lastRunTime > 0 ? new
Date(lastRunTime).toISOString() : 'N/A';
+ params.total = total;
+ params.passed = passedCount;
+ params.finished = finishedCount;
+ params.id = dir;
+
+ return params;
+ });
+}
+
+module.exports.delTestsRun = async function (hash) {
+ fse.removeSync(path.join(RESULTS_ROOT_DIR, hash));
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]