| <!-- | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you under the Apache License, Version 2.0 (the | |
| "License"); you may not use this file except in compliance | |
| with the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, | |
| software distributed under the License is distributed on an | |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| KIND, either express or implied. See the License for the | |
| specific language governing permissions and limitations | |
| under the License. | |
| --> | |
| <!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"> | |
| <link rel="shortcut icon" href="asset/echarts-logo.png"> | |
| <title>Visual Regression Testing Tool</title> | |
| </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 Testing Tool</h1> | |
| </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'"> | |
| <el-col :span="2"> | |
| <el-checkbox :indeterminate="isSelectAllIndeterminate" v-model="allSelected" @change="handleSelectAllChange"></el-checkbox> | |
| </el-col> | |
| <el-col :span="17"> | |
| <el-input v-model="searchString" size="mini" placeholder="Filter Tests"></el-input> | |
| </el-col> | |
| <el-col :span="2"> | |
| <el-button title="Sort By Failue Percentage" @click="toggleSort" size="mini" type="primary" icon="el-icon-sort">Sort</el-button> | |
| </el-col> | |
| </el-row> | |
| </div> | |
| <ul class="test-list"> | |
| <li v-for="(test, index) in tests" | |
| :title="test.name" | |
| :class="{active: currentTest && currentTest.name === test.name}" | |
| @click="changeTest($event.target, 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> | |
| <template v-if="test.status === 'finished'"> | |
| <el-tooltip | |
| v-if="test.actualErrors && test.actualErrors.length > 0" | |
| > | |
| <div slot="content">{{test.actualErrors.length}} Errors</div> | |
| <i class="el-icon-message-solid" | |
| style="color: #F56C6C" | |
| ></i> | |
| </el-tooltip> | |
| <el-tooltip v-else> | |
| <div slot="content">{{test.percentage}}% Passed</div> | |
| <el-progress | |
| type="circle" | |
| :width="20" | |
| :stroke-width="2" | |
| :percentage="test.percentage" | |
| :status="test.summary" | |
| ></el-progress> | |
| </el-tooltip> | |
| </template> | |
| <el-tooltip | |
| content="Not yet run" | |
| v-else-if="!(test.status === 'pending' && running)" | |
| > | |
| <i class="el-icon-question" | |
| style="color: #ccc;font-size: 20px;" | |
| ></i> | |
| </el-tooltip> | |
| <a :href="'#' + test.name" class="menu-link"> | |
| {{test.name}} | |
| <i v-if="test.actions" class="el-icon-video-camera-solid"></i> | |
| <span v-if="test.actions" style="font-size: 12px;color: #ccc;">({{test.actions}})</span> | |
| </a> | |
| </li> | |
| </ul> | |
| </el-aside> | |
| <el-main> | |
| <div class="test-run-controls"> | |
| <div class="test-run-row"> | |
| <div class="run-config-item"> | |
| <el-tooltip content="Show Result of All Test Runnings"> | |
| <div style="cursor: pointer;" @click="showAllTestsRuns"> | |
| <i style="font-size:20px;vertical-align:middle;display:inline-block;" class="el-icon-files"></i> | |
| <span style="vertical-align:middle;display:inline-block;">LIST OF RUNNING RESULTS</span> | |
| </div> | |
| </el-tooltip> | |
| </div> | |
| <div class="run-config-item"> | |
| <el-dropdown v-if="!running" split-button size="mini" title="Run" | |
| @click="run('selected')" | |
| @command="run" | |
| > | |
| <i class="el-icon-caret-right"></i> RUN ({{selectedTests.length}}) | |
| <el-dropdown-menu slot="dropdown" > | |
| <el-dropdown-item command="unfinished">Run unfinished ({{unfinishedTests.length}})</el-dropdown-item> | |
| <el-dropdown-item command="failed">Run failed ({{failedTests.length}})</el-dropdown-item> | |
| <el-dropdown-item command="all">Run all ({{fullTests.length}})</el-dropdown-item> | |
| </el-dropdown-menu> | |
| </el-dropdown> | |
| <el-button-group v-else> | |
| <el-button size="mini" :loading="true">Stop</el-button> | |
| <el-button title="Run" @click="stopTests" size="mini" icon="el-icon-close" style="padding-left: 3px;padding-right:3px;"></el-button> | |
| </el-button-group> | |
| <el-tooltip :content="'Finished ' + finishedPercentage + '%'"> | |
| <el-progress | |
| type="circle" | |
| :percentage="finishedPercentage" | |
| :width="20" | |
| :stroke-width="4" | |
| :show-text="false" | |
| ></el-progress> | |
| </el-tooltip> | |
| </div> | |
| </div> | |
| <div class="test-run-row"> | |
| <div class="run-config-item"> | |
| <span class="label"> | |
| Expected | |
| <el-tooltip content="Use Nightly Build"> | |
| <el-checkbox :disabled="running" v-model="runConfig.isExpectedNightly" size="mini"></el-checkbox> | |
| </el-tooltip> | |
| </span> | |
| <el-select :disabled="running" size="mini" v-model="runConfig.expectedVersion" placeholder="Select Version" | |
| :style="`width: ${runConfig.isExpectedNightly ? 160 : 80}px;`" | |
| > | |
| <el-option v-for="version in expectedVersionsList" :key="version" :label="version" :value="version"></el-option> | |
| </el-select> | |
| <!-- <i class="el-icon-link"></i> --> | |
| <span class="label"> | |
| Actual | |
| <el-tooltip content="Use Nightly Build"> | |
| <el-checkbox :disabled="running" v-model="runConfig.isActualNightly" size="mini"></el-checkbox> | |
| </el-tooltip> | |
| </span> | |
| <el-select :disabled="running" size="mini" v-model="runConfig.actualVersion" placeholder="Select Version" | |
| :style="`width: ${runConfig.isActualNightly ? 160 : 80}px;`" | |
| > | |
| <el-option v-for="version in actualVersionsList" :key="version" :label="version" :value="version"></el-option> | |
| </el-select> | |
| </div> | |
| <div class="run-config-item"> | |
| <span class="label">Renderer</span> | |
| <el-select :disabled="running" size="mini" style="width: 100px;" v-model="runConfig.renderer" placeholder="Select Renderer"> | |
| <el-option key="canvas" label="canvas" value="canvas"></el-option> | |
| <el-option key="svg" label="svg" value="svg"></el-option> | |
| </el-select> | |
| </div> | |
| <div class="run-config-item"> | |
| <span class="label">Coarse Pointer</span> | |
| <el-select :disabled="running" size="mini" style="width: 100px;" v-model="runConfig.useCoarsePointer" placeholder="auto"> | |
| <el-option key="auto" label="auto" value="auto"></el-option> | |
| <el-option key="true" label="true" value="true"></el-option> | |
| <el-option key="false" label="false" value="false"></el-option> | |
| </el-select> | |
| </div> | |
| <div class="run-config-item"> | |
| <span class="label">Threads</span> | |
| <el-select :disabled="running" size="mini" v-model="runConfig.threads" style="width: 58px"> | |
| <el-option v-for="t in [1, 2, 4, 6, 8]" :key="t" :label="t" :value="t"></el-option> | |
| </el-select> | |
| <!-- <el-slider style="width: 100px;" v-model="runConfig.threads" :step="1" :min="1" :max="8" show-stops></el-slider> --> | |
| </div> | |
| </div> | |
| </div> | |
| <!-------- Single Test Reusult -----------> | |
| <div v-if="currentTest" class="test-result"> | |
| <div class="title"> | |
| <el-progress | |
| v-if="currentTest.status === 'finished'" | |
| type="circle" | |
| :width="30" | |
| :stroke-width="4" | |
| :percentage="currentTest.percentage" | |
| :status="currentTest.summary" | |
| style="margin-top: 5px;" | |
| ></el-progress> | |
| <h3>{{currentTest.name}}</h3> | |
| </div> | |
| <div class="single-test-ops"> | |
| <el-button-group> | |
| <el-button :loading="running" size="mini" @click="runSingleTest(currentTest.name)" type="primary" icon="el-icon-caret-right">Run Single</el-button> | |
| <el-button :loading="running" size="mini" @click="runSingleTest(currentTest.name, true)">Replay</el-button> | |
| </el-button-group> | |
| <el-button size="mini" @click="open(currentTestUrl, '_blank')" icon="el-icon-link">Open Demo</el-button> | |
| <el-button size="mini" @click="open(currentTestRecordUrl, '_blank')" icon="el-icon-video-camera">Record Interaction</el-button> | |
| </div> | |
| <div v-if="currentTest.results.length > 0"> | |
| <div class="test-screenshots" v-for="(result, idx) in currentTest.results"> | |
| <!-- Not display title if it's same with previous --> | |
| <h4 v-if="result.desc !== (currentTest.results[idx - 1] && currentTest.results[idx - 1].desc)"> | |
| <i class="el-icon-s-operation"></i>{{result.desc || result.name}} | |
| </h4> | |
| <el-row :gutter="40" class="screenshots"> | |
| <el-col :span="8"> | |
| <el-card shadow="hover"> | |
| <div slot="header" class="clearfix"> | |
| <span>Expected - {{currentTest.expectedVersion || ''}}</span> | |
| <i title="Preview" class="el-icon-view preview" @click="preview(currentTest, 'expected')"></i> | |
| </div> | |
| <el-image fit="cover" :src="result.expected" :preview-src-list="[result.expected]"></el-image> | |
| </el-card> | |
| </el-col> | |
| <el-col :span="8"> | |
| <el-card shadow="hover"> | |
| <div slot="header" class="clearfix"> | |
| <span>Actual - {{currentTest.actualVersion || ''}}</span> | |
| <i title="Preview" class="el-icon-view preview" @click="preview(currentTest, 'actual')"></i> | |
| </div> | |
| <el-image fit="cover" :src="result.actual" :preview-src-list="[result.actual]"></el-image> | |
| </el-card> | |
| </el-col> | |
| <el-col :span="8"> | |
| <el-card shadow="hover"> | |
| <div slot="header" class="clearfix"> | |
| <span>Diff - {{result.diffRatio.toFixed(4)}}</span> | |
| </div> | |
| <el-image fit="cover" :src="result.diff" :preview-src-list="[result.diff]"></el-image> | |
| </el-card> | |
| </el-col> | |
| </el-row> | |
| </div> | |
| </div> | |
| <div v-else class="no-result"> | |
| No Result | |
| </div> | |
| <div class="test-errors" v-if="currentTest.expectedErrors.length > 0 || currentTest.actualErrors.length > 0"> | |
| <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" v-if="currentTest.expectedLogs.length > 0 || currentTest.actualLogs.length > 0"> | |
| <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> | |
| <el-dialog | |
| :visible.sync="showIframeDialog" | |
| :center="true" | |
| width="850px" | |
| > | |
| <div slot="title"> | |
| {{previewTitle}} | |
| <a target="_blank" :href="'../../' + previewTitle"><i class="el-icon-link"></i>Open in New Window</a> | |
| </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" v-loading="loadingTestsRuns"> | |
| <el-table-column property="expectedVersion" label="Expected" width="160"></el-table-column> | |
| <el-table-column property="actualVersion" label="Actual" width="160"></el-table-column> | |
| <el-table-column property="renderer" label="Renderer" width="100"></el-table-column> | |
| <el-table-column property="lastRunTime" label="Last Run" width="160"></el-table-column> | |
| <el-table-column property="diskSize" label="Disk Size" width="100"></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="Operations" | |
| 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> | |
| </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.15.1/lib/theme-chalk/index.css"> | |
| <script src="https://unpkg.com/element-ui@2.15.1/lib/index.js"></script> | |
| <script src="client.js"></script> | |
| <link rel="stylesheet" href="client.css"> | |
| </body> | |
| </html> |