This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a commit to branch test-autorun
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
The following commit(s) were added to refs/heads/test-autorun by this push:
new ea440f6 test: Improve visual regression test UI
ea440f6 is described below
commit ea440f6b2584ad60e528f29627e5122d92ce6e7f
Author: pissang <[email protected]>
AuthorDate: Thu Aug 29 20:33:55 2019 +0800
test: Improve visual regression test UI
---
test/runTest/blacklist.js | 4 +-
test/runTest/cli.js | 59 ++++++++++++++++-------
test/runTest/client/client.css | 107 ++++++++++++++++++++++++++++++++++++++---
test/runTest/client/client.js | 102 +++++++++++++++++++++++++++++++++++----
test/runTest/client/index.html | 62 +++++++++++++++++++-----
5 files changed, 287 insertions(+), 47 deletions(-)
diff --git a/test/runTest/blacklist.js b/test/runTest/blacklist.js
index e059607..77cdd23 100644
--- a/test/runTest/blacklist.js
+++ b/test/runTest/blacklist.js
@@ -1,4 +1,4 @@
module.exports = [
-'-cases.html',
-'geo-random-stream.html'
+ '-cases.html',
+ 'geo-random-stream.html'
];
\ No newline at end of file
diff --git a/test/runTest/cli.js b/test/runTest/cli.js
index b560072..69d3188 100644
--- a/test/runTest/cli.js
+++ b/test/runTest/cli.js
@@ -140,7 +140,6 @@ async function takeScreenshot(page, elementQuery, fileUrl,
desc, version) {
}
async function runTestPage(browser, fileUrl, version) {
-
const {keepWait, waitTimeout} = createWaitTimeout(3200);
const testResults = [];
let screenshotPromises = [];
@@ -176,10 +175,16 @@ async function runTestPage(browser, fileUrl, version) {
let pageFinishPromise = waitPageForFinish(page);
- await page.goto(`${origin}/test/${fileUrl}`, {
- waitUntil: 'networkidle2',
- timeout: 10000
- });
+ try {
+ await page.goto(`${origin}/test/${fileUrl}`, {
+ waitUntil: 'networkidle2',
+ timeout: 10000
+ });
+ }
+ catch(e) {
+ // TODO Timeout Error
+ console.error(e);
+ }
// Do auto screenshot for every 1 second.
let count = 1;
@@ -213,6 +218,7 @@ async function runTestPage(browser, fileUrl, version) {
}
async function runTest(browser, testOpt) {
+ testOpt.status === 'running';
const fileUrl = testOpt.fileUrl;
const expectedShots = await runTestPage(browser, fileUrl, '4.2.1');
const actualShots = await runTestPage(browser, fileUrl);
@@ -238,6 +244,7 @@ async function runTest(browser, testOpt) {
expected: getClientRelativePath(expected.screenshotPath),
diff: getClientRelativePath(diffPath),
name: actual.testName,
+ desc: actual.desc,
diffRatio
});
});
@@ -292,21 +299,37 @@ async function start() {
io.on('connect', socket => {
broadcast({tests});
+ // TODO Stop previous?
+ socket.on('run', async testsNameList => {
+ console.log(testsNameList);
+
+ const pendingTests = tests.filter(testOpt => {
+ return testsNameList.includes(testOpt.name);
+ });
+
+ for (let testOpt of pendingTests) {
+ // Reset all tests results
+ testOpt.status = 'pending';
+ testOpt.results = [];
+ }
+
+ broadcast({tests});
+
+ try {
+ for (let testOpt of pendingTests) {
+ await runTest(browser, testOpt);
+ broadcast({tests});
+ writeTestsToCache(tests);
+ }
+ }
+ catch(e) {
+ console.log(e);
+ }
+ });
});
- for (let testOpt of tests) {
- if (testOpt.status === 'finished') {
- continue;
- }
- console.log(`Running test ${testOpt.fileUrl}`)
- await runTest(browser, testOpt);
- broadcast({tests});
- writeTestsToCache(tests);
- }
+ // runTests(browser, tests, tests);
}
-start().catch(e => {
- console.log('Error during test');
- console.log(e);
-})
\ No newline at end of file
+start()
\ No newline at end of file
diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css
index 22ce528..62c1ca3 100644
--- a/test/runTest/client/client.css
+++ b/test/runTest/client/client.css
@@ -10,17 +10,112 @@
font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans
GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
}
-.menu-link {
- display: block;
+.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;
+}
+.nav-toolbar .controls {
+ margin-top: 10px;
+}
+
+.test-list {
+ overflow-x: hidden;
+ background: #293c55;
+ margin: 0;
+ padding: 0;
+}
+.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: 18px;
+ font-size: 14px;
+ line-height: 40px;
+ color: #f3f3f3;
+ margin-left: 3px;
+ cursor: pointer;
}
-.test-screenshots {
- margin-top: 50px;
+.test-list li.active {
+ background: #e43c59;
+}
+.test-list li:hover {
+ background: #162436;
+}
+.test-list li>* {
+ vertical-align: middle;
+ display: inline-block
}
-.test-screenshots img {
+.test-list .el-progress__text {
+ font-size: 12px!important;
+}
+
+.test-result {
+ margin-top: 80px;
+ padding: 0 20px;
+}
+
+.test-result img {
/* height: 200px; */
width: 100%;
+}
+.test-result h4 {
+ font-size: 30px;
+ font-weight: 200;
+ margin-left: -20px;
+}
+
+
+::-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
index 5bc96b6..716fdad 100644
--- a/test/runTest/client/client.js
+++ b/test/runTest/client/client.js
@@ -1,32 +1,114 @@
const socket = io();
+
+function processTestsData(tests) {
+ tests.forEach(test => {
+ let passed = 0;
+ 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'
+ }
+ test.selected = false;
+ });
+ return tests;
+}
+
socket.on('connect', () => {
console.log('Connected');
-
const app = new Vue({
el: '#app',
data: {
- tests: [],
- selectedTestName: ''
+ fullTests: [],
+ currentTestName: '',
+ sortBy: 'name',
+ searchString: '',
+ running: false,
+
+ allSelected: false
},
computed: {
- selectedTest() {
- let selectedTest = this.tests.find(item => item.name ===
this.selectedTestName);
- if (!selectedTest) {
- selectedTest = this.tests[0];
+ tests() {
+ let sortFunc = this.sortBy === 'name'
+ ? (a, b) => a.name.localeCompare(b.name)
+ : (a, b) => a.percentage - b.percentage;
+
+ if (!this.searchString) {
+ return this.fullTests.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;
+ },
+
+ isSelectAllIndeterminate() {
+ if (!this.tests.length) {
+ return true;
+ }
+ return this.tests.some(test => {
+ return test.selected !== this.tests[0].selected;
+ });
+ }
+ },
+ 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;
+ },
+ runSelectedTests() {
+ this.running = true;
+ const tests = this.fullTests.filter(test => {
+ return test.selected;
+ }).map(test => {
+ return test.name
+ });
+ if (tests.length > 0) {
+ socket.emit('run', tests);
}
- return selectedTest;
+ },
+ stopTests() {
+ this.running = false;
+ socket.emit('stop');
}
}
});
app.$el.style.display = 'block';
socket.on('broadcast', msg => {
- app.tests = msg.tests;
+ app.fullTests = processTestsData(msg.tests);
});
function updateTestHash() {
let testName = window.location.hash.slice(1);
- app.selectedTestName = testName;
+ app.currentTestName = testName;
}
updateTestHash();
diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html
index 8bfdf3b..e9797ec 100644
--- a/test/runTest/client/index.html
+++ b/test/runTest/client/index.html
@@ -8,22 +8,58 @@
<body>
<div id="app" style="display: none">
<el-container id="main">
- <el-header>
- <h1>Visual Regression Test</h1>
+ <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="250px">
- <el-menu class="test-list">
- <el-menu-item v-for="test in tests">
+ <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
+ 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-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>
+ </div>
+ </div>
+ <ul class="test-list">
+ <li v-for="test in tests"
+ :title="test.name"
+ :class="{active: currentTest && currentTest.name ===
test.name}"
+ @click.self="goto(test.name)"
+ >
+ <el-checkbox v-model="test.selected"></el-checkbox>
+ <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>
- </el-menu-item>
- </el-menu>
+
+ </li>
+ </ul>
</el-aside>
<el-main>
- <div v-if="selectedTest">
- <div class="test-screenshots" v-for="result in
selectedTest.results">
- <h4 class="md-title">{{result.name}}</h4>
- <el-row :gutter="20">
+ <div v-if="currentTest">
+ <div class="test-result" 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">
@@ -52,6 +88,10 @@
</el-col>
</el-row>
</div>
+
+ <div class="test-result-nav">
+
+ </div>
</div>
</el-main>
</el-container>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]