mirror of
https://github.com/bulwarkmail/native.git
synced 2026-10-31 16:06:32 +00:00
72 lines
2.5 KiB
JavaScript
72 lines
2.5 KiB
JavaScript
#!/usr/bin/env node
|
|
// Summarise Maestro's debug output (~/.maestro/tests) without its secrets.
|
|
//
|
|
// The JSON there records every command with its arguments, so typed
|
|
// passwords are in it; it is never uploaded. This prints, per flow, the
|
|
// command types and their status (no arguments), and for a failed command
|
|
// the element tree Maestro saw (labels, ids and bounds), which is what a
|
|
// failing selector needs. run-flows.sh scrubs the secret values from the
|
|
// output as well.
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
const root = process.argv[2];
|
|
const out = [];
|
|
|
|
function walkFiles(dir) {
|
|
if (!fs.existsSync(dir)) return [];
|
|
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((e) => {
|
|
const p = path.join(dir, e.name);
|
|
return e.isDirectory() ? walkFiles(p) : [p];
|
|
});
|
|
}
|
|
|
|
function tree(node, depth, lines) {
|
|
if (!node || typeof node !== 'object') return;
|
|
const a = node.attributes || {};
|
|
const label = [a.accessibilityText, a.text, a.hintText, a['resource-id'] && `#${a['resource-id']}`]
|
|
.filter(Boolean)
|
|
.filter((v, i, all) => all.indexOf(v) === i)
|
|
.join(' | ');
|
|
if (label) lines.push(`${' '.repeat(Math.min(depth, 12))}${label} ${a.bounds || ''}${a.focused === 'true' ? ' [focused]' : ''}`);
|
|
for (const c of node.children || []) tree(c, depth + 1, lines);
|
|
}
|
|
|
|
function findHierarchy(obj, seen = new Set()) {
|
|
if (!obj || typeof obj !== 'object' || seen.has(obj)) return null;
|
|
seen.add(obj);
|
|
if (obj.attributes && Array.isArray(obj.children)) return obj;
|
|
for (const v of Object.values(obj)) {
|
|
const h = findHierarchy(v, seen);
|
|
if (h) return h;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
for (const file of walkFiles(root).filter((f) => /commands-.*\.json$/.test(f))) {
|
|
let data;
|
|
try {
|
|
data = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
} catch {
|
|
continue;
|
|
}
|
|
out.push(`== ${path.basename(file)}`);
|
|
for (const entry of Array.isArray(data) ? data : []) {
|
|
const command = entry.command || {};
|
|
const type = Object.keys(command).find((k) => command[k]) || '?';
|
|
const status = entry.metadata?.status || '?';
|
|
out.push(` ${status.padEnd(9)} ${type}`);
|
|
if (status === 'FAILED') {
|
|
const err = entry.metadata?.error?.message;
|
|
if (err) out.push(` error: ${String(err).slice(0, 300)}`);
|
|
const h = findHierarchy(entry.metadata);
|
|
if (h) {
|
|
const lines = [];
|
|
tree(h, 0, lines);
|
|
out.push(...lines.slice(0, 250).map((l) => ` ${l}`));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
process.stdout.write(out.join('\n') + '\n');
|