test-web: Add run date and "copy run command" button to results header
This commit is contained in:
parent
1af74d1a7c
commit
778402640a
3 changed files with 59 additions and 8 deletions
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/Error.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibWebView/Application.h>
|
||||
|
||||
|
|
@ -37,6 +38,7 @@ public:
|
|||
Vector<ByteString> test_globs;
|
||||
|
||||
ByteString python_executable_path;
|
||||
String invocation_command_line;
|
||||
|
||||
bool dump_gc_graph { false };
|
||||
bool fail_fast { false };
|
||||
|
|
|
|||
|
|
@ -452,6 +452,7 @@ static ErrorOr<void> generate_result_files(ReadonlySpan<Test> tests, ReadonlySpa
|
|||
{
|
||||
auto& app = Application::the();
|
||||
bool const has_helper_logs = FileSystem::exists(LexicalPath::join(app.results_directory, "helper-process-logs.html"sv).string());
|
||||
auto const generated_at = UnixDateTime::now();
|
||||
|
||||
// Count results
|
||||
size_t fail_count = 0;
|
||||
|
|
@ -482,6 +483,8 @@ static ErrorOr<void> generate_result_files(ReadonlySpan<Test> tests, ReadonlySpa
|
|||
js.append("const RESULTS_DATA = {\n"sv);
|
||||
js.appendff(" \"summary\": {{ \"total\": {}, \"fail\": {}, \"timeout\": {}, \"crashed\": {}, \"skipped\": {} }},\n",
|
||||
s_total_tests, fail_count, timeout_count, crashed_count, skipped_count);
|
||||
js.appendff(" \"generatedAt\": {},\n", generated_at.seconds_since_epoch());
|
||||
js.appendff(" \"invocationCommandLine\": {},\n", JsonValue(app.invocation_command_line).serialized());
|
||||
js.appendff(" \"hasLogs\": {},\n", has_helper_logs ? "true" : "false");
|
||||
js.append(" \"tests\": [\n"sv);
|
||||
|
||||
|
|
@ -1724,6 +1727,7 @@ ErrorOr<int> ladybird_main(Main::Arguments arguments)
|
|||
#else
|
||||
auto app = TRY(TestWeb::Application::create(arguments, OptionalNone {}));
|
||||
#endif
|
||||
app->invocation_command_line = MUST(String::join(' ', arguments.strings));
|
||||
|
||||
if (app->repeat_count > 1 && app->rebaseline) {
|
||||
warnln("Error: --repeat cannot be used together with --rebaseline.");
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
|
|
@ -60,6 +60,12 @@
|
|||
gap: 12px;
|
||||
}
|
||||
|
||||
.title-timestamp {
|
||||
color: var(--text-secondary);
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
h1::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
|
|
@ -274,6 +280,25 @@
|
|||
border-color: var(--accent-green);
|
||||
}
|
||||
|
||||
#copy-run-command-btn {
|
||||
margin-left: auto;
|
||||
width: auto;
|
||||
height: auto;
|
||||
padding: 10px;
|
||||
gap: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
#copy-run-command-btn .stat-label {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.copy-btn-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
color: var(--text-muted);
|
||||
transition: transform 0.2s ease;
|
||||
|
|
@ -582,7 +607,11 @@
|
|||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>Test Results</h1>
|
||||
<h1>
|
||||
<span>Test Results</span>
|
||||
<span class="title-timestamp" id="page-timestamp"></span>
|
||||
</h1>
|
||||
<button class="copy-btn" id="copy-run-command-btn"></button>
|
||||
<div class="search-box">
|
||||
<span class="search-icon">🔍</span>
|
||||
<input type="text" id="search" placeholder="Filter tests..." autocomplete="off">
|
||||
|
|
@ -603,11 +632,27 @@
|
|||
let currentIndex = -1;
|
||||
let testElements = [];
|
||||
|
||||
function setCopyButtonContents(btn, icon) {
|
||||
if (btn.id !== 'copy-run-command-btn') return btn.innerHTML = icon;
|
||||
btn.innerHTML = `<span class="stat-label">Copy Run Cmd</span><span class="copy-btn-icon">${icon}</span>`;
|
||||
}
|
||||
|
||||
function renderHeader(data) {
|
||||
const date = new Date(data.generatedAt * 1000);
|
||||
const pad2 = (value) => String(value).padStart(2, '0');
|
||||
document.getElementById('page-timestamp').textContent = `${date.getFullYear()}/${pad2(date.getMonth() + 1)}/${pad2(date.getDate())} at ${pad2(date.getHours())}:${pad2(date.getMinutes())}:${pad2(date.getSeconds())}`;
|
||||
const copyRunCommandButton = document.getElementById('copy-run-command-btn');
|
||||
setCopyButtonContents(copyRunCommandButton, copySvg);
|
||||
copyRunCommandButton.title = data.invocationCommandLine;
|
||||
copyRunCommandButton.onclick = e => copyText(e, copyRunCommandButton, data.invocationCommandLine);
|
||||
}
|
||||
|
||||
function loadResults() {
|
||||
if (typeof RESULTS_DATA === 'undefined') {
|
||||
document.getElementById('content').innerHTML = '<div class="empty-state"><h2>No Results</h2><p>results.js not found</p></div>';
|
||||
return;
|
||||
}
|
||||
renderHeader(RESULTS_DATA);
|
||||
renderResults(RESULTS_DATA);
|
||||
setupKeyboardNav();
|
||||
}
|
||||
|
|
@ -665,7 +710,7 @@
|
|||
${item.result ? `<span class="result-badge ${item.result}">${item.result}</span>` : ''}
|
||||
${item.mode ? `<span class="mode-badge">${item.mode}</span>` : ''}
|
||||
<span class="test-name">${item.name}</span>
|
||||
${item.result ? `<button class="copy-btn" onclick="copyTestName(event, this, '${item.name}')" title="Copy test path">${copySvg}</button>` : ''}
|
||||
${item.result ? `<button class="copy-btn" onclick="copyText(event, this, '${item.name}')" title="Copy test path">${copySvg}</button>` : ''}
|
||||
<span class="expand-icon">▶</span>
|
||||
</div>
|
||||
<div class="test-content">`;
|
||||
|
|
@ -701,13 +746,13 @@
|
|||
return { bar, tabs };
|
||||
}
|
||||
|
||||
function copyTestName(event, btn, name) {
|
||||
event.stopPropagation();
|
||||
navigator.clipboard.writeText(name).then(function() {
|
||||
btn.innerHTML = checkSvg;
|
||||
function copyText(event, btn, text) {
|
||||
event?.stopPropagation();
|
||||
navigator.clipboard.writeText(text).then(function() {
|
||||
setCopyButtonContents(btn, checkSvg);
|
||||
btn.classList.add('copied');
|
||||
setTimeout(function() {
|
||||
btn.innerHTML = copySvg;
|
||||
setCopyButtonContents(btn, copySvg);
|
||||
btn.classList.remove('copied');
|
||||
}, 1500);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue