183 lines
6.3 KiB
Handlebars
183 lines
6.3 KiB
Handlebars
<div class="junit">
|
|
<div id="junit-suites">
|
|
<p class="coltitle">Test suites:</p>
|
|
<ul>
|
|
<li><button class="active">Show all</button></li>
|
|
{{#each suites.suites}}
|
|
<li data-status="{{#if errors == 0 && failures == 0}}success{{else}}failure{{/if}}"><button>{{name}}</button></li>
|
|
{{/each}}
|
|
</ul>
|
|
</div>
|
|
<div id="junit-cases">
|
|
<p class="coltitle">Test cases:</p>
|
|
<p id="junit-statusfilter" class="colsubtitle">
|
|
<button data-status="all">All <b>?</b></button>
|
|
<button data-status="success">OK <b>?</b></button>
|
|
<button data-status="failure">Failed <b>?</b></button>
|
|
<button data-status="error">Error <b>?</b></button>
|
|
<button data-status="flaky">Flaky <b>?</b></button>
|
|
<button data-status="skipped">Skipped <b>?</b></button>
|
|
</p>
|
|
<ul>
|
|
{{~#each suites.suites ~}}{{ let suite_name = &name }}
|
|
{{#each cases}}
|
|
<li data-suite="{{ suite_name }}" data-status="{{ status.id() }}">
|
|
<button>{{#if let Some(cn) = &classname}}<span>{{ cn }}::</span>{{/if}}{{ original_name }}</button>
|
|
<div class="pvcontent">
|
|
<h2><i class="gg-{{#if status.id() == "success"}}check-o{{else if status.id() == "skipped"}}block{{else if status.id() == "flaky"}}danger{{else}}close-o{{/if}}"></i> {{name}}</h2>
|
|
<p class="badges"><span>{{ this.status_txt() }}</span><span>{{ crate::util::time_to_ms(time) }}ms</span></p>
|
|
{{~#if let Some(msg) = status.message() ~}}
|
|
<pre><code>{{msg.message}}{{msg.text}}</code></pre>
|
|
{{~/if}}
|
|
{{~#if let Some(ref stdout) = system_out ~}}
|
|
<pre><code>{{stdout}}</code></pre>
|
|
{{~/if}}
|
|
{{~#if let Some(ref stderr) = system_err ~}}
|
|
<pre><code>{{stderr}}</code></pre>
|
|
{{~/if}}
|
|
{{~#each retries ~}}
|
|
<h3>Failed attempt #{{index}}</h3>
|
|
<p class="badges"><span>{{ crate::util::time_to_ms(time) }}ms</span></p>
|
|
{{~#if let Some(msg) = status.message() ~}}
|
|
<pre><code>{{msg.message}}{{msg.text}}</code></pre>
|
|
{{~/if}}
|
|
{{~#if let Some(ref stdout) = system_out ~}}
|
|
<pre><code>{{stdout}}</code></pre>
|
|
{{~/if}}
|
|
{{~#if let Some(ref stderr) = system_err ~}}
|
|
<pre><code>{{stderr}}</code></pre>
|
|
{{~/if}}
|
|
{{~/each}}
|
|
</div>
|
|
</li>
|
|
{{/each}}
|
|
{{~/each}}
|
|
</ul>
|
|
</div>
|
|
<div id="junit-preview">
|
|
<div id="preview-margin"></div>
|
|
<div class="prose">
|
|
<p class="light">Select a test case to show details</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
|
|
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT
|
|
|
|
let preview;
|
|
let previewMargin;
|
|
let statusFilterBtns = {};
|
|
let filterSuite = null;
|
|
let filterStatus = "failure";
|
|
let lastScrollPos = 0;
|
|
let previewMarginH = 0;
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
preview = document.querySelector("#junit-preview > .prose");
|
|
previewMargin = document.getElementById("preview-margin");
|
|
|
|
statusFilterBtns = {};
|
|
const btnElms = document.getElementById("junit-statusfilter").children;
|
|
for (let i=0; i<btnElms.length; i++) {
|
|
const elm = btnElms[i];
|
|
statusFilterBtns[elm.attributes["data-status"].value] = elm;
|
|
}
|
|
|
|
document.querySelectorAll("#junit-suites li > button").forEach((btn) => {
|
|
btn.addEventListener("click", () => filterBySuite(btn));
|
|
});
|
|
document.querySelectorAll("#junit-statusfilter > button").forEach((btn) => {
|
|
btn.addEventListener("click", () => filterByStatus(btn));
|
|
});
|
|
document.querySelectorAll("#junit-cases li > button").forEach((btn) => {
|
|
btn.addEventListener("click", selectTestCase);
|
|
});
|
|
doFilter();
|
|
|
|
document.addEventListener("scroll", () => {
|
|
const delta = lastScrollPos - document.documentElement.scrollTop;
|
|
if (delta > 0) {
|
|
previewMarginH = Math.max(previewMarginH - delta, 0);
|
|
lastScrollPos = document.documentElement.scrollTop;
|
|
previewMargin.style.marginTop = previewMarginH + "px";
|
|
}
|
|
});
|
|
});
|
|
|
|
function setCls(elm, cls, val) {
|
|
if (val) elm.classList.add(cls);
|
|
else elm.classList.remove(cls);
|
|
}
|
|
|
|
function selectTestCase(event) {
|
|
let elm = event.target.closest("li");
|
|
const pvc = elm.querySelector(".pvcontent");
|
|
if (pvc && preview) {
|
|
preview.innerHTML = pvc.innerHTML;
|
|
preview.parentElement.setAttribute("data-status", elm.attributes["data-status"].value);
|
|
|
|
previewMarginH = Math.max(document.documentElement.scrollTop - 72, 20);
|
|
lastScrollPos = document.documentElement.scrollTop;
|
|
previewMargin.style.marginTop = previewMarginH + "px";
|
|
|
|
resetBtns("junit-cases ul");
|
|
elm.querySelector("button").classList.add("active");
|
|
if (window.innerWidth < 1000) preview.scrollIntoView();
|
|
}
|
|
}
|
|
|
|
function resetBtns(id) {
|
|
document.querySelectorAll(`#${id} .active`).forEach((elm) => {
|
|
elm.classList.remove("active");
|
|
});
|
|
}
|
|
|
|
function doFilter() {
|
|
const nStatus = {all: 0};
|
|
document.querySelectorAll("#junit-cases li").forEach((elm) => {
|
|
const status = elm.attributes["data-status"].value;
|
|
const isSuite = filterSuite === null || filterSuite === elm.attributes["data-suite"].value;
|
|
const vis = isSuite && (filterStatus === "all" || filterStatus === status);
|
|
setCls(elm, "hidden", !vis);
|
|
if (isSuite) {
|
|
nStatus[status] = nStatus[status] ? nStatus[status]+1 : 1;
|
|
nStatus.all++;
|
|
}
|
|
});
|
|
|
|
if (!nStatus[filterStatus]) {
|
|
filterStatus = "all";
|
|
doFilter();
|
|
return;
|
|
}
|
|
|
|
Object.entries(statusFilterBtns).forEach(([status, elm]) => {
|
|
const n = nStatus[status] ?? 0;
|
|
elm.children[0].textContent = n;
|
|
if (status === filterStatus) elm.classList.add("active");
|
|
else elm.classList.remove("active");
|
|
setCls(elm, "hidden", n === 0);
|
|
});
|
|
setCls(document.getElementById("junit-cases"), "filtered", filterSuite);
|
|
}
|
|
|
|
function filterBySuite(btn) {
|
|
const suite = btn.textContent;
|
|
if (suite) {
|
|
filterSuite = suite === "Show all" ? null : suite;
|
|
doFilter();
|
|
resetBtns("junit-suites");
|
|
btn.classList.add("active");
|
|
}
|
|
}
|
|
|
|
function filterByStatus(btn) {
|
|
filterStatus = btn.attributes["data-status"].value;
|
|
doFilter();
|
|
}
|
|
|
|
// @license-end
|
|
|
|
</script>
|