async function* resultTable({ parse, inputs, parts, expected, skip = [] }) {
function render(data) {
return htl.html`<table>
<thead>
<tr>
<th>Case</th>
${parts.map(
(d, i) => htl.html`<th style="text-align: end">Part ${i + 1}</th>`
)}
</tr>
</thead>
<tbody>
${Object.entries(data).map(
([k, v]) =>
htl.html`<tr>
<td>${k}</td>
${v.map((d) => {
return htl.html`<td style="text-align: end">
${
d.duration !== undefined
? htl.html`<span style="font-size: 0.7em; color: #888;">(${d.duration.toFixed(
1
)}ms)</span>`
: ""
}
${
!d.running &&
!d.error &&
d.expected !== undefined &&
d.actual !== undefined
? d.expected === d.actual
? "✅"
: "❌"
: ""
}
${d.running ? "⏰" : d.error ?? d.actual}
${
d.skip
? htl.html`<span style="font-size: 0.7em; color: #888;">N/A</span>`
: ""
}
</td>`;
})}
</tr>`
)}
</tbody>
</table>`;
}
let results = Object.fromEntries(
Object.keys(inputs).map((name) => [
name,
parts.map((d, idx) => ({
expected: expected?.[name]?.[idx],
actual: undefined,
error: undefined,
running: false
}))
])
);
yield render(results);
for (const [name, input] of Object.entries(inputs)) {
for (const [part, idx] of Array.from(parts, (d, i) => [d, i])) {
let target = results[name][idx];
if (skip.some((s) => s.input === name && s.part === idx + 1)) {
target.skip = true;
continue;
}
target.running = true;
yield render(results);
let start = performance.now();
let parsed = parse(input);
try {
target.actual = await part(parsed);
} catch (err) {
target.error = err;
}
let end = performance.now();
target.duration = end - start;
target.running = false;
yield render(results);
}
}
}