Files
buzz/desktop/src/testing/e2eBridgeCustomHarnesses.ts
npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 5862b3109e fix(desktop): close D-12, D-15, F8, C-10 gaps before Thufir pass 1/3
D-12: Revert mobile/pubspec.lock to origin/main.  The meta 1.17→1.18 /
test 1.30→1.31 churn was a no-source-change lockfile bump introduced by
accident; reverting eliminates the unrelated diff.

D-15: Add OpenClaw execution-locus note to the preset's install_hint.
Eva's finding: openclaw acp executes tools inside the Gateway daemon, not
in the Desktop process.  Desktop-injected BUZZ_* env vars reach the
openclaw harness process itself but do NOT automatically propagate to
the Gateway's execution environment.  The install_hint now surfaces this
caveat so users who need BUZZ_* credentials at execution time know they
must set them on the Gateway's own environment.

F8 (onboarding navigate test): New pure-logic test file
postOnboardingNav.test.mjs proves the App.tsx postOnboardingNav
useEffect predicate — navigateAfterComplete does not fire before
machine.stage reaches 'ready', fires exactly once on the ready
transition, is cleared after firing (no double-fire), fires immediately
if nav arrives while already ready, and carries the exact
{to: '/settings', search: {section: 'agents'}} shape from
MachineOnboardingFlow's navigateToAgentSettings action.

C-10 (e2eBridge + handler tests): Extract save_custom_harness /
delete_custom_harness handler logic into e2eBridgeCustomHarnesses.ts
(exported module-level functions + mockCustomHarnesses Map +
resetMockCustomHarnesses).  Wire the handlers into e2eBridge.ts:
  - mockCustomHarnesses imported and appended to discover_acp_providers
    results so saved custom harnesses appear in future discovery calls
  - case 'save_custom_harness' → handleSaveCustomHarness
  - case 'delete_custom_harness' → handleDeleteCustomHarness
New test file e2eBridgeCustomHarnesses.test.mjs (14 tests across 3
describe groups) proves: save → store, non-empty env preserved,
empty env absent, same-ID edit replaces, rename removes old + inserts
new, delete removes, delete idempotent, Map reference is shared.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
2026-07-25 01:55:03 -04:00

81 lines
2.6 KiB
TypeScript

/**
* In-memory custom harness store for the e2e bridge.
*
* Extracted as a separate module so the handler logic can be unit-tested
* independently of the full e2eBridge.ts context (which requires a browser
* environment and full Playwright setup).
*/
import type { RawAcpRuntimeCatalogEntry } from "../shared/api/tauri.ts";
/** In-memory store for custom harnesses saved via `save_custom_harness`. */
export const mockCustomHarnesses = new Map<string, RawAcpRuntimeCatalogEntry>();
/** Reset the store between tests. */
export function resetMockCustomHarnesses(): void {
mockCustomHarnesses.clear();
}
/**
* Handle `save_custom_harness`.
*
* Persists the definition into `mockCustomHarnesses` so that the next
* `discover_acp_providers` call includes it. Mirrors the Rust command's
* return shape: an `AcpRuntimeCatalogEntry` for the saved harness.
*/
export function handleSaveCustomHarness(args: {
definition?: {
id?: string;
label?: string;
command?: string;
args?: string[];
env?: Record<string, string>;
installInstructionsUrl?: string;
installHint?: string;
};
originalId?: string | null;
}): RawAcpRuntimeCatalogEntry {
const def = args.definition ?? {};
const id = def.id ?? "";
const originalId = args.originalId ?? null;
// On rename: remove the old entry so the old id is no longer in the catalog.
if (originalId && originalId !== id) {
mockCustomHarnesses.delete(originalId);
}
const entry: RawAcpRuntimeCatalogEntry = {
id,
label: def.label ?? id,
avatar_url: "",
availability: "not_installed", // PATH not probed in e2e mock
command: def.command ?? null,
binary_path: null,
default_args: def.args ?? [],
mcp_command: null,
install_hint: def.installHint ?? "",
install_instructions_url: def.installInstructionsUrl ?? "",
can_auto_install: false,
requires_external_cli: true,
underlying_cli_path: null,
node_required: false,
auth_status: { status: "not_applicable" },
source: "custom",
// Omit definition_env when the env map is empty — mirrors Rust's BTreeMap
// serialization which skips empty maps so the field is absent on the wire.
definition_env:
def.env && Object.keys(def.env).length > 0 ? def.env : undefined,
login_hint: undefined,
};
mockCustomHarnesses.set(id, entry);
return entry;
}
/**
* Handle `delete_custom_harness`.
* Removes the harness from the in-memory store. Idempotent (not-found is OK).
*/
export function handleDeleteCustomHarness(args: { id?: string }): void {
const id = args.id ?? "";
mockCustomHarnesses.delete(id);
}