Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions playground/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ The Diagnosis screen emits a per-host markdown report via "Copy report". Aggrega
| `src/lib/example-runner.ts` | Transpiles each rustdoc `ts` example via sucrase, runs it inside an `AsyncFunction` with `truapi`, `console`, rxjs, and an ambient `assert` as bindings. Failure is explicit: an example fails iff it throws (via `assert(...)`, a timeout, or any uncaught error); `console.*` is pure output. A tracking Proxy auto-unsubscribes inner `.subscribe(...)` calls so subscriptions clean up when the run ends or the user navigates away. |
| `src/lib/monaco-setup.ts` | Configures Monaco's TS worker: registers the bundled `@parity/truapi` types (`truapi-dts`), every rxjs `.d.ts`, and an ambient block (`declare const truapi: Client`, `assert`, `crypto`, `Uint8Array` hex helpers) so examples typecheck without manual imports. Defines the light/dark themes that match the design tokens. |
| `src/lib/auto-test.ts` | Runs each method's example and reports pass / fail. A method passes when its example resolves within the timeout and fails when it throws (the thrown/`assert` message plus any logs become the failure output); unary and subscription examples are awaited identically. `runDiagnosis` runs every method one at a time, in service order; methods that prompt the user (signing, permission/resource requests) block on their host dialog before the run continues. `runSingleTest` replays one method (used by the Diagnosis row replay). |
| `src/lib/diagnosis-report.ts` | Renders the diagnosis results as a copy-pasteable GitHub-flavoured markdown table: a `## Truapi <Web\|Desktop\|Android\|iOS> Diagnosis` title (host mode via `detectHostMode` — a native host (Electron UA or `__HOST_WEBVIEW_MARK__`) is split by user-agent into Desktop / Android / iOS, a browser iframe ⇒ Web) a `**N success · N failed**` summary line, and one row per method. Skipped methods are reported as failed (`❌`) with the skip reason in the Details column, so every truapi method stays in the compatibility matrix (the aggregator keeps only `✅`/`❌` cells). Deterministic for a given set of results (no timestamp). `renderReportMarkdown(…, { dropSuccessDetails })` emits a compact variant (success-row details blanked, failures kept) for the length-limited issue URL; `reportIssueUrl` caps the whole URL and falls back to a "paste from clipboard" body when a report is still too large. Consumed by the explorer's matrix aggregator. |
| `src/lib/diagnosis-report.ts` | Renders deterministic copy-pasteable GitHub-flavoured markdown: a `## Truapi <Web\|Desktop\|Android\|iOS> Diagnosis` title, a `**N success · N failed · N skipped**` summary, and one row per method. Passes use `✅`, genuine failures use `❌`, and intentional prerequisite skips use `⏭`; the explorer aggregator maps skips to unmeasured (`null`) rather than claiming support or failure. `renderReportMarkdown(…, { dropSuccessDetails })` blanks bulky success details for the length-limited issue URL while retaining failure and skip reasons. `reportIssueUrl` caps the URL and falls back to a clipboard-paste prompt. |
| `src/lib/host-api-bridge.ts` | Just `stringify`, the JSON-with-bigint helper shared across components. |
| `src/components/ExampleEditor.tsx` | Monaco editor wrapper. Auto-folds `// #region helpers` blocks on mount. |
| `src/components/MethodView.tsx` | Per-method view: signature link to cargo doc, Example / Output tabs, status LED, Run / Stop buttons. Output is the example's `console.*` log; an explicit `assert`/error throw flips the LED to error and shows the thrown message. |
| `src/components/DiagnosisView.tsx` | Diagnosis screen (own sidebar entry): purpose + login/phone instructions, a Run button, a live per-method log (queued → processing… → success/failed) with per-row expand + replay, a summary showing success / failed counts (skipped methods are shown as failed, with the skip reason as their detail), and Copy report / Submit report buttons. Submit copies the full report to the clipboard and opens a pre-filled GitHub issue carrying a compact variant of it. |
| `src/components/DiagnosisView.tsx` | Diagnosis screen (own sidebar entry): purpose + login/phone instructions, a Run button, a live per-method log (queued → processing… → success / failed / skipped) with per-row expand + replay, a summary showing separate success / failed / skipped counts, and Copy report / Submit report buttons. Submit copies the full report to the clipboard and opens a pre-filled GitHub issue carrying a compact variant of it. |
| `src/components/ServiceTable.tsx` / `CommandPalette.tsx` | Method browser and ⌘K search. The browser also hosts the Diagnosis entry. |
| `src/app/page.tsx` | Root: connection status, selection state, deep-link sync via `pushState` + `popstate`. |

Expand Down
17 changes: 7 additions & 10 deletions playground/src/components/DiagnosisView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ interface Row {
service: string;
method: string;
status: TestStatus;
// A skipped method is displayed as failed; this flags it so the e2e gate can
// tell an intentional skip apart from a genuine failure.
skipped: boolean;
output?: string;
}
Expand All @@ -47,27 +45,25 @@ export function DiagnosisView({
const [copied, setCopied] = useState(false);
const [expandedId, setExpandedId] = useState<string | null>(null);

const { rows, hasResults, passCount, failCount } = useMemo(() => {
const { rows, hasResults, passCount, failCount, skipCount } = useMemo(() => {
const out: Row[] = [];
let pass = 0;
let fail = 0;
let skipped = 0;
for (const svc of services) {
for (const m of svc.methods) {
const id = `${svc.name}/${m.name}`;
const entry = testResults[id];
const rawStatus = entry?.status ?? "idle";
// Skipped methods are shown as failed (their skip reason is the detail)
// so the view stays a pass/fail summary and every method is accounted
// for — matching the compatibility matrix.
const status = rawStatus === "skipped" ? "fail" : rawStatus;
const status = entry?.status ?? "idle";
if (status === "pass") pass++;
else if (status === "fail") fail++;
else if (status === "skipped") skipped++;
out.push({
id,
service: svc.name,
method: m.name,
status,
skipped: rawStatus === "skipped",
skipped: status === "skipped",
output: entry?.output,
});
}
Expand All @@ -77,6 +73,7 @@ export function DiagnosisView({
hasResults: Object.keys(testResults).length > 0,
passCount: pass,
failCount: fail,
skipCount: skipped,
};
}, [services, testResults]);

Expand Down Expand Up @@ -176,7 +173,7 @@ export function DiagnosisView({
data-testid="diagnosis-summary"
data-has-fail={!isRunning && failCount > 0}
>
{passCount} success · {failCount} failed
{passCount} success · {failCount} failed · {skipCount} skipped
</span>
)}
{hasResults && !isRunning && (
Expand Down
13 changes: 9 additions & 4 deletions playground/src/lib/auto-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ const LIVE_ALLOCATION_TIMEOUT_MS = 420_000;

// Services skipped wholesale in the diagnosis until hosts wire them up.
const SKIPPED_SERVICES = new Set(["Chat", "Coin Payment", "Payment"]);
// Individual methods skipped while the host surface is intentionally deferred.
const SKIPPED_METHODS = new Set(["Account/create_account_proof"]);
// Individual methods skipped when Diagnosis cannot establish their prerequisite.
const SKIPPED_REASON: Record<string, string> = {
"Account/create_account_proof": "host surface intentionally deferred",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one should work now, we should not skip it.

"Chain/stop_transaction":
"requires an operation id from a live transaction broadcast",
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this since you fix the test in #318

// Methods that trigger a host permission/signing prompt, so they need the
// longer signing-class timeout to allow for the user to respond.
const LONG_TIMEOUT_METHODS = new Set([
Expand Down Expand Up @@ -69,10 +73,11 @@ async function runOne({
});
return;
}
if (SKIPPED_METHODS.has(id)) {
const skippedReason = SKIPPED_REASON[id];
if (skippedReason) {
onUpdate(id, {
status: "skipped",
output: "host surface intentionally deferred",
output: skippedReason,
});
return;
}
Expand Down
22 changes: 9 additions & 13 deletions playground/src/lib/diagnosis-report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,33 +49,29 @@ export function renderReportMarkdown(
const mode = meta.mode ?? detectHostMode();
let pass = 0;
let fail = 0;
let skipped = 0;
const rows: string[] = [];
for (const svc of services) {
for (const m of svc.methods) {
const id = `${svc.name}/${m.name}`;
const entry = results[id];
const status = entry?.status ?? "idle";
// Skipped methods are reported as failed so every truapi method stays in
// the compatibility matrix (the aggregator keeps only ✅/❌ cells); the
// reason the method was skipped travels in the Details column.
const reportStatus = status === "skipped" ? "fail" : status;
if (reportStatus === "pass") pass++;
else if (reportStatus === "fail") fail++;
if (status === "pass") pass++;
else if (status === "fail") fail++;
else if (status === "skipped") skipped++;
// The issue-URL variant drops success-row details (bulky response
// payloads) to keep the URL under GitHub's length limit; failures keep
// their (short) details.
// payloads) to keep the URL under GitHub's length limit; failures and
// intentional skips keep their (short) details.
const detail =
meta.dropSuccessDetails && reportStatus === "pass"
? ""
: detailCell(entry);
rows.push(`| \`${id}\` | ${ICON[reportStatus]} | ${detail} |`);
meta.dropSuccessDetails && status === "pass" ? "" : detailCell(entry);
rows.push(`| \`${id}\` | ${ICON[status]} | ${detail} |`);
}
}

const lines: string[] = [];
lines.push(`## Truapi ${mode} Diagnosis`);
lines.push("");
lines.push(`**${pass} success · ${fail} failed**`);
lines.push(`**${pass} success · ${fail} failed · ${skipped} skipped**`);
lines.push("");
lines.push("| Method | Status | Details |");
lines.push("| --- | --- | --- |");
Expand Down
9 changes: 3 additions & 6 deletions playground/tests/e2e/dotli-diagnosis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -578,13 +578,10 @@ async function runDiagnosisOnce(page: Page): Promise<{
if (report.trim().length === 0) {
throw new Error("diagnosis report markdown is empty");
}
// Skipped methods render as failed (and appear failed in the matrix), but they
// are intentional gaps — exclude them from the CI hard-fail gate so only
// genuine failures fail the run.
// Neutral prerequisite skips use data-status="skipped"; only genuine
// failures enter the CI hard-fail gate.
const failedMethods = await frame
.locator(
'[data-testid="diagnosis-row"][data-status="fail"]:not([data-skipped="true"]) .diag__name',
)
.locator('[data-testid="diagnosis-row"][data-status="fail"] .diag__name')
.allInnerTexts();

await frame.locator('[data-testid="diagnosis-copy-report"]').click();
Expand Down