RobotFramework 报告汉化
RobotFramework 报告汉化可以更方便非自动化人员查看测试报告,汉化后的报告如下。 
自动化测试报告汉化方法:
这两个文件是输出报告时使用的模版,它们分别是report.html和view.js,在目录”Python home”\Lib\site-packages\robot\htmldata\rebot下面
下载后直接替换此2个文件即可。
下载地址:地址1
修改里面的内容。


report.html
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Expires" content="-1"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="Generator" content=""> <link rel="icon" type="image/x-icon" href="data:image/x-icon;base64,AAABAAEAEBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAAAIAAAAAAAAAAAAAEAAAAAAAAAAAAAAAJEBoACtnfgA5cYYAERsiAEx2lAAbKkQAcazBACZCVwAcM1cAK0ucAAMDBQAnQncASG+FABkoVQAyWmgA6f8SgvH/Ij99+GLyIinyJfn/Yi//KSLzUy9iZogpIld3/4JVVTkid7vyUjNVNVJEAGOZ6Z7pXwAABpmZkRiLAAAGiJZpmGAAAEEt3SXdxAAATC7o/u3EAAC8MRZpjasAAAY1VVVTYAAABKqqqqpAAAAADKqq4AAAAAAAv4sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMADAADgAwAA4AcAAOAHAADgBwAAwAcAAOAHAADgDwAA8A8AAPg/AAD+fwAA"> <link rel="stylesheet" type="text/css" href="common.css" media="all"> <link rel="stylesheet" type="text/css" href="report.css" media="all"> <link rel="stylesheet" type="text/css" href="print.css" media="print"> <link rel="stylesheet" type="text/css" href="../common/js_disabled.css" media="all"> <link rel="stylesheet" type="text/css" href="../common/doc_formatting.css" media="all"> <script type="text/javascript" src="../lib/jquery.min.js"></script> <script type="text/javascript" src="../lib/jquery.tmpl.min.js"></script> <script type="text/javascript" src="../lib/jquery.tablesorter.min.js"></script> <script type="text/javascript" src="../lib/jsxcompressor.min.js"></script> <script type="text/javascript" src="fileloading.js"></script> <script type="text/javascript" src="model.js"></script> <script type="text/javascript" src="util.js"></script> <script type="text/javascript" src="testdata.js"></script> <script type="text/javascript" src="view.js"></script> <script type="text/javascript" src="../common/storage.js"></script> <!-- JS MODEL --><script type="text/javascript" src="../testdata/data.js"></script> <title></title> </head> <body> <div id="javascript-disabled"> <h1>打开报告失败</h1> <ul> <li>请验证在您的浏览器设置中 <b>已启用JavaScript.</b></li> <li>确定您使用的是<b>比较新的浏览器</b>. 推荐使用Firefox 3.5, IE 8, 或者与他版本相当的浏览器以及比它们版本靠后的浏览器ß.</li> <li>检查在您的浏览器上面是否 <b>JavaScript错误日志</b>的消息. 如果您怀疑这是一个报告的bug请报告技术团队.</li> </ul> </div> <script type="text/javascript">removeJavaScriptDisabledWarning();</script> <div id="header"></div> <div id="statistics-container"></div> <div id="test-details-container"></div> <script type="text/javascript"> $(document).ready(function () { try { var topsuite = window.testdata.suite(); } catch (error) { addJavaScriptDisabledWarning(error); return; } setBackground(topsuite); initLayout(topsuite.name, 'Report'); storage.init('report'); addSummary(topsuite); addStatistics(); addDetails(); window.prevLocationHash = ''; window.onhashchange = showDetailsByHash; }); function setBackground(topsuite) { var color; if (topsuite.criticalFailed) color = window.settings.background.fail; else if (topsuite.totalFailed) color = window.settings.background.nonCriticalFail; else color = window.settings.background.pass; $('body').css('background-color', color); } function addSummary(topsuite) { var opts = {logURL: window.settings.logURL}; $.tmpl('summaryTableTemplate', topsuite, opts).insertAfter($('#header')); } function addDetails() { addCustomSortersForDetails(); if (window.location.hash) showDetailsByHash(); else renderTotalSelector(); } function addCustomSortersForDetails() { $.tablesorter.addParser({ id: 'criticality', type: 'numeric', is: function(s) { return false; // do not auto-detect }, format: function(s) { return s === 'yes' ? 0 : 1; } }); $.tablesorter.addParser({ id: 'times', type: 'text', is: function(s) { return false; // do not auto-detect }, format: function(s) { return s.substring(0, 21); // return only start time } }); } function showDetailsByHash() { // Cannot use window.location.hash because Firefox incorrectly decodes it: // http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash var hash = window.location.href.split('#').slice(1).join('#'); if (!hash || hash == window.prevLocationHash) return; var parts = hash.split('?'); var name = parts.shift(); var query = parts.join('?'); if (name == 'search') { var params = util.parseQueryString(query); searchExecuted(params.suite || '', params.test || '', params.include || '', params.exclude || ''); return } query = decodeURIComponent(query); var action = {'totals': totalDetailSelected, 'tags': tagDetailSelected, 'suites': suiteDetailSelected}[name]; if (action) action(query); } function totalDetailSelected(name) { renderTotalSelector(name); if (name) { renderTotalDetails(name); updatePrintSelector(name == 'critical' ? 'Critical Tests' : 'All Tests'); } scrollToSelector('totals', name); } function renderTotalSelector(name) { var args = {linkTarget: (name) ? 'totals?'+name : 'totals', totalTabStatus: 'detail-tab-selected'}; renderSelector(args, 'totalDetailsSelectorTemplate', {selected: name}); } function renderTotalDetails(name) { var index = (name == 'critical') ? 0 : 1; var stat = window.testdata.statistics().total[index]; var tests = getTotalTests(name); stat.totalTime = calculateTotalTime(tests); $.tmpl('tagOrTotalDetailsTemplate', stat).appendTo('#details-header'); drawTestDetailsTable(tests, true); } function updatePrintSelector(name, info) { if (info) name += ' (' + info + ')'; $('#print-selector').html(name); } function tagDetailSelected(name) { renderTagSelector(name); if (name) { var tag = findTag(name); if (tag) { renderTagDetails(tag); updatePrintSelector(name, tag.info); } } scrollToSelector('tags', name); } function findTag(name) { var tags = window.testdata.statistics().tag; for (var i = 0, len = tags.length; i < len; i++) { if (tags[i].label == name) return tags[i]; } return null; } function renderTagSelector(name) { var args = {linkTarget: (name) ? 'tags?'+name : 'tags', tagTabStatus: 'detail-tab-selected'}; var stats = {tags: window.testdata.statistics().tag, selected: name}; renderSelector(args, 'tagDetailsSelectorTemplate', stats); } function renderTagDetails(tag) { var tests = getTestsHavingTag(tag); tag.totalTime = calculateTotalTime(tests); $.tmpl('tagOrTotalDetailsTemplate', tag).appendTo('#details-header'); drawTestDetailsTable(tests, true); } function suiteDetailSelected(id) { renderSuiteSelector(id); if (id) renderSuiteDetails(id); scrollToSelector('suites', id); } function renderSuiteSelector(id) { var args = {linkTarget: (id) ? 'suites?'+id : 'suites', suiteTabStatus: 'detail-tab-selected'}; var stats = {suites: window.testdata.statistics().suite, selected: id}; renderSelector(args, 'suiteDetailsSelectorTemplate', stats); } function renderSuiteDetails(id) { window.testdata.ensureLoaded(id, function (ids) { var suite = window.testdata.findLoaded(id); var opts = {logURL: window.settings.logURL}; $.tmpl('suiteDetailsTemplate', suite, opts).appendTo('#details-header'); drawTestDetailsTable(suite.allTests(), false); updatePrintSelector(suite.fullName); }); } function searchExecuted(suite, test, include, exclude) { renderSearchSelector(suite, test, include, exclude); if (suite || test || include || exclude) { renderSearchDetails(suite, test, include, exclude); scrollToSelector('search' + '?suite=' + encodeURIComponent(suite) + '&test=' + encodeURIComponent(test) + '&include=' + encodeURIComponent(include) + '&exclude=' + encodeURIComponent(exclude)); } else { scrollToSelector('search'); } } function renderSearchSelector(suite, test, include, exclude) { var args = {linkTarget: (suite || test || include || exclude) ? ('search?suite=' + suite + '&test=' + test + '&include=' + include + '&exclude=' + exclude) : 'search', searchTabStatus: 'detail-tab-selected'}; var search = {suite: suite, test: test, include: include, exclude: exclude}; renderSelector(args, 'searchSelectorTemplate', search); } function renderSearchDetails(suite, test, include, exclude) { var tests = searchTests(util.escape(suite), util.escape(test), util.escape(include), util.escape(exclude)); var passed = calculatePassed(tests); var stats = {total: tests.length, pass: passed, fail: tests.length - passed, totalTime: calculateTotalTime(tests)}; $.tmpl('tagOrTotalDetailsTemplate', stats).appendTo('#details-header'); drawTestDetailsTable(tests, true); } function searchTests(suitePattern, testPattern, includePattern, excludePattern) { var tests; if (suitePattern) tests = window.testdata.suite().searchTestsInSuite(suitePattern); else tests = window.testdata.suite().allTests(); return util.filter(tests, function (test) { if (testPattern && !test.matchesNamePattern(testPattern)) return false; if (includePattern && !test.matchesTagPattern(includePattern)) return false; return !(excludePattern && test.matchesTagPattern(excludePattern)); }); } function scrollToSelector(base, query) { $('#test-details-container').css('min-height', $(window).height()); var anchor = query ? base + '?' + encodeURIComponent(query) : base; window.location.hash = window.prevLocationHash = anchor; } function renderSelector(args, template, stats) { window.elementsToRender = []; var container = $('#test-details-container'); container.empty(); $.tmpl('detailsHeaderTemplate', args).appendTo(container); $.tmpl(template, stats).appendTo(container); } function drawTestDetailsTable(tests, sortByStatus) { if (!tests.length) return; renderTestDetailsHeader(); window.elementsToRender = tests; var target = $('#test-details').find('tbody'); renderTestDetails(sortByStatus, target); } function renderTestDetailsHeader() { var header = $.tmpl('testDetailsTableTemplate'); hideHiddenDetailsColumns(header); header.appendTo('#test-details-container'); } function sortByStatus(t1, t2) { if (t1.status != t2.status) return t1.status == 'FAIL' ? -1 : 1; if (t1.isCritical != t2.isCritical) return t1.isCritical ? -1 : 1; return t1.fullName < t2.fullName ? -1 : 1; } function getTestsHavingTag(tag) { return window.testdata.suite().searchTestsByTag(tag).sort(sortByStatus); } function getTotalTests(name) { if (name == 'critical') return window.testdata.suite().criticalTests().sort(sortByStatus); return window.testdata.suite().allTests().sort(sortByStatus); } function calculateTotalTime(tests) { var total = 0; for (var i = 0, len = tests.length; i < len; i++) total += tests[i].times.elapsedMillis; return util.formatElapsed(total); } function calculatePassed(tests) { var passed = util.filter(tests, function (test) { return test.status == 'PASS'; }); return passed.length; } function renderTestDetails(sortByStatus, target) { if (!window.elementsToRender.length) return; var tests = popUpTo(window.elementsToRender, 50); renderTestDetailsRows(tests, target); if (window.elementsToRender.length) setTimeout(function () {renderTestDetails(sortByStatus, target);}, 0); else configureTableSorter(sortByStatus); } function renderTestDetailsRows(tests, target) { var rows = $.tmpl('testDetailsTableRowTemplate', tests, {logURL: window.settings.logURL}); rows.find('a').click(stopPropagation); hideHiddenDetailsColumns(rows); rows.appendTo(target); } function configureTableSorter(sortByStatus) { var config = {headers: {3: {sorter: 'criticality'}, 6: {sortInitialOrder: 'desc'}, 7: {sorter: 'times'}}, selectorSort: '.details-col-header'}; if (sortByStatus) config['sortList'] = [[4, 0], [3, 0]]; $('#test-details').tablesorter(config); } function popUpTo(list, upTo) { var result = []; while (list.length > 0 && result.length < upTo) result.push(list.shift()); return result; } function toggleDetailsColumn(name) { var column = $('.details-col-' + name); column.toggleClass('hidden'); var hidden = column.hasClass('hidden'); storage.set(name, hidden ? 'hidden' : 'visible'); column.find('.details-col-toggle').html(hidden ? '…' : '×'); } function hideHiddenDetailsColumns(elem) { var names = ['doc', 'tags', 'msg', 'elapsed', 'times']; for (var i = 0; i < names.length; i++) { var name = names[i]; if (storage.get(name, 'visible') == 'hidden') { var column = elem.find('.details-col-' + name); column.addClass('hidden'); column.find('.details-col-toggle').html('…'); } } } </script> <script type="text/x-jquery-tmpl" id="summaryTableTemplate"> <h2>综合信息</h2> <table class="details"> <tr> <th>状态:</th> {{if criticalFailed}} <td><a href="#totals?critical" onclick="totalDetailSelected('critical')" class="fail">${criticalFailed} 重要的测试{{if criticalFailed != 1}}{{/if}} 失败</a></td> {{else totalFailed}} <td><a href="#totals?critical" onclick="totalDetailSelected('critical')" class="pass">所有重要的测试都通过了</a></td> {{else}} <td><a href="#totals?all" onclick="totalDetailSelected('all')" class="pass">所有的测试都通过了</a></td> {{/if}} </tr> {{if doc()}} <tr> <th>说明:</th> <td class="doc">{{html doc()}}</td> </tr> {{/if}} {{each metadata}} <tr> <th>{{html $value[0]}}:</th> <td class="doc">{{html $value[1]}}</td> </tr> {{/each}} {{if times.startTime != 'N/A'}} <tr> <th>开始时间:</th> <td>${times.startTime}</td> </tr> {{/if}} {{if times.endTime != 'N/A'}} <tr> <th>结束时间:</th> <td>${times.endTime}</td> </tr> {{/if}} <tr> <th>消耗时间:</th> <td>${times.elapsedTime}</td> </tr> {{if $item.logURL}} <tr> <th>日志文件:</th> <td><a href="${$item.logURL}">${$item.logURL}</a></td> </tr> {{/if}} </table> </script> <script type="text/x-jquery-tmpl" id="totalStatisticsRowTemplate"> <tr onclick="totalDetailSelected('${type}')" class="row-${$item.index}"> <td class="stats-col-name"> <div class="stat-name"> <a href="#totals?${type}">{{html label}}</a> </div> </td> {{tmpl($data) 'statColumnsTemplate'}} </tr> </script> <script type="text/x-jquery-tmpl" id="tagStatisticsRowTemplate"> <tr onclick="tagDetailSelected('${label}')" class="row-${$item.index}"> <td class="stats-col-name" title="{{html doc}}"> <div class="stat-name"> <a href="#tags?${label}">{{html label}}</a> {{if info}}(${info}){{/if}} </div> <div class="tag-links"> {{each links}} <span>[<a href="{{html $value.url}}" onclick="stopPropagation(event)" title="{{html $value.url}}">{{html $value.title}}</a>]</span> {{/each}} </div> </td> {{tmpl($data) 'statColumnsTemplate'}} </tr> </script> <script type="text/x-jquery-tmpl" id="suiteStatisticsRowTemplate"> <tr onclick="suiteDetailSelected('${id}')" class="row-${$item.index}"> <td class="stats-col-name" title="{{html label}}"> <div class="stat-name"> <a href="#suites?${id}"><span class="parent-name">{{html formatParentName}}</span>{{html name}}</a> </div> </td> {{tmpl($data) 'statColumnsTemplate'}} </tr> </script> <script type="text/x-jquery-tmpl" id="detailsHeaderTemplate"> <h2 id="${linkTarget}">测试详情</h2> <ul id="detail-tabs"> <li class="${totalTabStatus} detail-tab"> <a href="#totals" onclick="renderTotalSelector()">总共</a> </li> <li class="${tagTabStatus} detail-tab"> <a href="#tags" onclick="renderTagSelector()">标签</a> </li> <li class="${suiteTabStatus} detail-tab"> <a href="#suites" onclick="renderSuiteSelector()">测试集</a> </li> <li class="${searchTabStatus} detail-tab"> <a href="#search" onclick="renderSearchSelector()">搜索</a> </li> </ul> </script> <script type="text/x-jquery-tmpl" id="totalDetailsSelectorTemplate"> <table class="details" id="details-header"> <tr class="selector"> <th>类型:</th> <td id="normal-selector"> <input id="radio-critical" type="radio" name="totals-radio" onclick="totalDetailSelected('critical')" {{if selected == 'critical'}}checked="checked"{{/if}}> <label for="radio-critical">重要的测试</label><br> <input id="radio-all" type="radio" name="totals-radio" onclick="totalDetailSelected('all')" {{if selected == 'all'}}checked="checked"{{/if}}> <label for="radio-all">所有的测试</label> </td> <td id="print-selector"></td> </tr> </table> </script> <script type="text/x-jquery-tmpl" id="tagDetailsSelectorTemplate"> <table class="details" id="details-header"> <tr class="selector"> <th>名称:</th> <td id="normal-selector"> <select id="tag-detail-selector" onchange="tagDetailSelected(this.options[this.selectedIndex].value)"> <option value="">选择标签...</option> {{each tags}} <option value="${$value.label}" {{if $value.label == selected}}selected="selected"{{/if}}> {{html $value.label}} {{if $value.info}}(${$value.info}){{/if}} </option> {{/each}} </select> </td> <td id="print-selector"></td> </tr> </table> </script> <script type="text/x-jquery-tmpl" id="suiteDetailsSelectorTemplate"> <table class="details" id="details-header"> <tr class="selector"> <th>名称:</th> <td id="normal-selector"> <select id="suite-detail-selector" onchange="suiteDetailSelected(this.options[this.selectedIndex].value)"> <option value="">选择测试集...</option> {{each suites}} <option value="${$value.id}" {{if $value.id == selected}}selected="selected"{{/if}}> {{html $value.label}} </option> {{/each}} </select> </td> <td id="print-selector"></td> </tr> </table> </script> <script type="text/x-jquery-tmpl" id="searchSelectorTemplate"> <form action="javascript:void(0)"> <table class="details" id="details-header"> <tr class="selector first-selector"> <th><label for="search-suite">Suite:</label></th> <td><input id="search-suite" type="text" value="${suite}"></td> </tr> <tr class="selector middle-selector"> <th><label for="search-test">Test:</label></th> <td><input id="search-test" type="text" value="${test}"></td> </tr> <tr class="selector middle-selector"> <th><label for="search-include">Include:</label></th> <td><input id="search-include" type="text" value="${include}"></td> </tr> <tr class="selector middle-selector"> <th><label for="search-exclude">Exclude:</label></th> <td><input id="search-exclude" type="text" value="${exclude}"></td> </tr> <tr class="selector last-selector" id="search-buttons"> <th></th> <td> <input type="submit" value="Search" onclick="searchExecuted($('#search-suite').val(), $('#search-test').val(), $('#search-include').val(), $('#search-exclude').val())"> <input type="button" value="Clear" onclick="$('#search-suite').val(''); $('#search-test').val(''); $('#search-include').val(''); $('#search-exclude').val('')"> <a href="javascript:void(0)" onclick="$('#search-help').toggle()" title="搜索帮助开关.">帮助</a> </td> </tr> <tr id="search-help" style="display: none"> <th></th> <td> <div> <h3>搜索框</h3> <p> 测试用例能够通过测试集合和测试的名字搜到,也能通过标记搜到。如果使用多个搜索 关键字,那么搜到的将会是包含所有关键字的测试用例。 搜索框包含如下语义 <em>‑‑测试集</em>, <em>‑‑测试</em>, <em>‑‑包含</em> 和 <em>‑‑排除</em> 的选项. </p> <table class="search-help-examples"> <col class="help-item"> <col class="help-explanation"> <col class="help-examples> <tr> <th>字段</th> <th>释义</th> <th>例子</th> </tr> <tr> <td>测试集</td> <td> 测试集所包含的测试.它的匹配模式为测试集的名字或者包含上层测试集的全名. </td> <td>My Suite<br>Root.Parent.Sui*</td> </tr> <tr> <td>测试</td> <td> 包含所有匹配的测试. 它的匹配模式为测试的名字和包含上层测试集的全名. </td> <td>Test*<br>Root.Pa*.T???</td> </tr> <tr> <td>包含</td> <td> 包含匹配标签的测试 </td> <td>smoke<br>bug-*</td> </tr> <tr> <td>排除</td> <td> 不包含匹配标签的测试. </td> <td>slow<br>feature-4?</td> </tr> </table> <h3>匹配模式</h3> <p> 所有的搜索支持<em>*</em>和<em>?</em>,通配符会忽略大小写,空格,下划线. 标签搜索还支持 <em>AND</em>,<em>OR</em>和<em>NOT</em> (大小写敏感) 这些结合操作符. 如果操作符同时使用, 它们的优先级, 从高到低是 <em>AND</em>, <em>OR</em>, <em>NOT</em>. 请查看 <em>简单匹配模式</em> 和 <em>标签匹配模式</em>段落: <a href="http://robotframework.org/robotframework/#user-guide">Robot Framework用户使用指南</a>版本2.8.4或者最新版本来获取详细信息. </p> <table class="search-help-examples"> <col class="help-item"> <col class="help-explanation"> <col class="help-examples> <tr> <th>模式</th> <th>描述</th> <th>例子</th> </tr> <tr> <td>*</td> <td>匹配一切,即使它是空的.</td> <td>f*<br>sprint-*</td> </tr> <tr> <td>?</td> <td>匹配单个字符.</td> <td>f??<br>sprint-1?</td> </tr> <tr> <td>AND</td> <td>如果所有的模式都匹配成功.</td> <td>foo AND bar<br>x AND y* AND z??</td> </tr> <tr> <td>OR</td> <td>任何一个模式匹配成功.</td> <td>foo OR bar<br>x OR y* OR z1 AND z2</td> </tr> <tr> <td>NOT</td> <td>如果前面匹配成功,那么就匹配不成功,取反搜索.</td> <td>foo NOT bar<br>* NOT id-* AND smoke</td> </tr> </table> </div> </td> </tr> </table> </form> </script> <script type="text/x-jquery-tmpl" id="tagOrTotalDetailsTemplate"> <tr> <th>状态:</th> <td>${total} 总计, ${pass} 通过, {{if fail}}<span class="fail">${fail} 失败</span>{{else}}<span class="pass">0 失败</span>{{/if}}</td> </tr> {{if doc}} <tr> <th>说明:</th> <td>{{html doc}}</td> </tr> {{/if}} {{if combined}} <tr> <th>匹配:</th> <td>{{html combined}}</td> </tr> {{/if}} {{if links}}{{if links.length}} <tr> <th>链接:</th> <td>{{each links}}<a href="{{html $value.url}}" title="{{html $value.url}}">{{html $value.title}}</a> {{/each}}</td> </tr> {{/if}}{{/if}} <tr> <th>总共用时:</th> <td>${totalTime}</td> </tr> </script> <script type="text/x-jquery-tmpl" id="suiteDetailsTemplate"> <tr> <th>状态:</th> <td>{{tmpl($data) 'suiteStatusMessageTemplate'}}</td> </tr> {{if doc()}} <tr> <th>说明:</th> <td class="doc">{{html doc()}}</td> </tr> {{/if}} {{each metadata}} <tr> <th>{{html $value[0]}}:</th> <td class="doc">{{html $value[1]}}</td> </tr> {{/each}} {{if message()}} <tr> <th>Message:</th> <td class="message">{{html message()}}</td> </tr> {{/if}} <tr> <th>开始/结束 时间:</th> <td>${times.startTime} / ${times.endTime}</td> </tr> <tr> <th>耗时时间:</th> <td>${times.elapsedTime}</td> </tr> {{if $item.logURL}} <tr> <th>日志文件:</th> <td><a href="${$item.logURL}#${id}" title="{{html fullName}}">${$item.logURL}#${id}</a></td> </tr> {{/if}} </script> <script type="text/x-jquery-tmpl" id="testDetailsTableTemplate"> <table id="test-details"> <thead> <tr> <th class="details-col-name" title="名称"> <div class='details-col-header'>名称</div> </th> <th class="details-col-doc" title="说明"> <div class='details-col-toggle' onclick="toggleDetailsColumn('doc')">×</div> <div class='details-col-header'>说明</div> </th> <th class="details-col-tags" title="标签"> <div class='details-col-toggle' onclick="toggleDetailsColumn('tags')">×</div> <div class='details-col-header'>标签</div> </th> <th class="details-col-crit" title="重要"> <div class='details-col-header'>重要</div> </th> <th class="details-col-status" title="状态"> <div class='details-col-header'>状态</div> </th> <th class="details-col-msg" title="消息"> <div class='details-col-toggle' onclick="toggleDetailsColumn('msg')">×</div> <div class='details-col-header'>消息</div> </th> <th class="details-col-elapsed" title="耗时"> <div class='details-col-toggle' onclick="toggleDetailsColumn('elapsed')">×</div> <div class='details-col-header'>耗时</div> </th> <th class="details-col-times" title="开始/结束"> <div class='details-col-toggle' onclick="toggleDetailsColumn('times')">×</div> <div class='details-col-header'>开始/结束</div> </th> </tr> </thead> <tbody></tbody> </table> </script> <script type="text/x-jquery-tmpl" id="testDetailsTableRowTemplate"> {{if $item.logURL}} <tr onclick="location = '${$item.logURL}#${id}'" title="{{html fullName}}"> <td class="details-col-name"> <div><a href="${$item.logURL}#${id}"><span class="parent-name">{{html formatParentName}}</span>{{html name}}</a></div> </td> {{else}} <tr title="{{html fullName}}"> <td class="details-col-name"> <div><span class="parent-name">{{html formatParentName}}</span>{{html name}}</div> </td> {{/if}} <td class="details-col-doc"><div class="doc details-limited">{{html doc()}}</div></td> <td class="details-col-tags"><div>{{html tags.join(', ')}}</div></td> <td class="details-col-crit"><div>{{if isCritical}}是{{else}}否{{/if}}</div></td> <td class="details-col-status"><div class="${status.toLowerCase()}">${status}</div></td> <td class="details-col-msg"><div class="message details-limited">{{html message()}}</div></td> <td class="details-col-elapsed"><div>${times.elapsedTime}</div></td> <td class="details-col-times"><div>${times.startTime}<br>${times.endTime}</div></td> </tr> </script> </body> </html>
view.js
function removeJavaScriptDisabledWarning() { // Not using jQuery here for maximum speed document.getElementById('javascript-disabled').style.display = 'none'; } function addJavaScriptDisabledWarning(error) { if (window.console) console.error('Opening failed: ' + error.name + ': ' + error.message); document.getElementById('javascript-disabled').style.display = 'block'; } function initLayout(suiteName, type) { parseTemplates(); setTitle(suiteName, type); addHeader(); addReportOrLogLink(type); } function parseTemplates() { $('script[type="text/x-jquery-tmpl"]').map(function (idx, elem) { $.template(elem.id, elem.text); }); } function setTitle(suiteName, type) { var givenTitle = window.settings.title; var title = givenTitle ? givenTitle : suiteName + " Test " + type; document.title = util.unescape(title); } function addHeader() { $.tmpl('<h1>${title}</h1>' + '<div id="generated">' + '<span>\u4ea7\u751f\u4e8e<br>${generated}</span><br>' + '<span id="generated-ago">${ago} \u4e4b\u524d</span>' + '</div>' + '<div id="top-right-header">' + '<div id="report-or-log-link"><a href="#"></a></div>' + '</div>', { generated: window.output.generatedTimestamp, ago: util.createGeneratedAgoString(window.output.generatedMillis), title: document.title }).appendTo($('#header')); } function addReportOrLogLink(myType) { var url; var text; var container = $('#report-or-log-link'); if (myType == 'Report') { url = window.settings.logURL; text = 'LOG'; } else { url = window.settings.reportURL; text = 'REPORT'; } if (url) { container.find('a').attr('href', url); container.find('a').text(text); } else { container.remove(); } } function addStatistics() { var statHeaders = '<th class="stats-col-stat">\u603b\u8ba1</th>' + '<th class="stats-col-stat">\u901a\u8fc7</th>' + '<th class="stats-col-stat">\u5931\u8d25</th>' + '<th class="stats-col-elapsed">\u8017\u65f6</th>' + '<th class="stats-col-graph">\u901a\u8fc7/\u5931\u8d25</th>'; var statTable = '<h2>\u6d4b\u8bd5\u7edf\u8ba1</h2>' + '<table class="statistics" id="total-stats"><thead><tr>' + '<th class="stats-col-name">\u7ea7\u522b\u7edf\u8ba1</th>' + statHeaders + '</tr></thead></table>' + '<table class="statistics" id="tag-stats"><thead><tr>' + '<th class="stats-col-name">\u6807\u7b7e\u7edf\u8ba1</th>' + statHeaders + '</tr></thead></table>' + '<table class="statistics" id="suite-stats"><thead><tr>' + '<th class="stats-col-name">\u6d4b\u8bd5\u96c6\u7edf\u8ba1</th>' + statHeaders + '</tr></thead></table>'; $(statTable).appendTo('#statistics-container'); util.map(['total', 'tag', 'suite'], addStatTable); addTooltipsToElapsedTimes(); enableStatisticsSorter(); } function addTooltipsToElapsedTimes() { $('.stats-col-elapsed').attr('title', 'Total execution time of these test cases. ' + 'Excludes suite setups and teardowns.'); $('#suite-stats').find('.stats-col-elapsed').attr('title', 'Total execution time of this test suite.'); } function enableStatisticsSorter() { $.tablesorter.addParser({ id: 'statName', type: 'numeric', is: function(s) { return false; // do not auto-detect }, format: function(string, table, cell, cellIndex) { // Rows have class in format 'row-<index>'. var index = $(cell).parent().attr('class').substring(4); return parseInt(index); } }); $(".statistics").tablesorter({ sortInitialOrder: 'desc', headers: {0: {sorter:'statName', sortInitialOrder: 'asc'}, 5: {sorter: false}} }); } function addStatTable(tableName) { var stats = window.testdata.statistics()[tableName]; if (tableName == 'tag' && stats.length == 0) { renderNoTagStatTable(); } else { renderStatTable(tableName, stats); } } function renderNoTagStatTable() { $('<tbody><tr class="row-0">' + '<td class="stats-col-name">No Tags</td>' + '<td class="stats-col-stat"></td>' + '<td class="stats-col-stat"></td>' + '<td class="stats-col-stat"></td>' + '<td class="stats-col-elapsed"></td>' + '<td class="stats-col-graph">' + '<div class="empty-graph"></div>' + '</td>' + '</tr></tbody>').appendTo('#tag-stats'); } function renderStatTable(tableName, stats) { var template = tableName + 'StatisticsRowTemplate'; var tbody = $('<tbody></tbody>'); for (var i = 0, len = stats.length; i < len; i++) { $.tmpl(template, stats[i], {index: i}).appendTo(tbody); } tbody.appendTo('#' + tableName + '-stats'); } $.template('statColumnsTemplate', '<td class="stats-col-stat">${total}</td>' + '<td class="stats-col-stat">${pass}</td>' + '<td class="stats-col-stat">${fail}</td>' + '<td class="stats-col-elapsed">${elapsed}</td>' + '<td class="stats-col-graph">' + '{{if total}}' + '<div class="graph">' + '<div class="pass-bar" style="width: ${passWidth}%" title="${passPercent}%"></div>' + '<div class="fail-bar" style="width: ${failWidth}%" title="${failPercent}%"></div>' + '</div>' + '{{else}}' + '<div class="empty-graph"></div>' + '{{/if}}' + '</td>' ); $.template('suiteStatusMessageTemplate', '${critical} critical test, ' + '${criticalPassed} passed, ' + '<span class="{{if criticalFailed}}fail{{else}}pass{{/if}}">${criticalFailed} failed</span><br>' + '${total} test total, ' + '${totalPassed} passed, ' + '<span class="{{if totalFailed}}fail{{else}}pass{{/if}}">${totalFailed} failed</span>' ); // For complete cross-browser experience.. // http://www.quirksmode.org/js/events_order.html function stopPropagation(event) { var event = event || window.event; event.cancelBubble = true; if (event.stopPropagation) event.stopPropagation(); }

浙公网安备 33010602011771号