openclaw/extensions/browser/plugin-registration.node-host-laziness.test.ts
Peter Steinberger 3c4c111b0f
feat: automatically update idle headless nodes (#151545)
* feat(node): update headless runtimes automatically when idle

Stage private packaged node runtimes and activate only after all owned work
and cleanup settle. Preserve pairing and launch options, keep automatic
activations at least 12 hours apart, and leave shared-state migration and
Gateway installation ownership with the normal updater.

Document defaults, opt-outs, runtime version discovery, and recovery.
Support recoverable Windows selector replacement across service restarts.

Refs #151462

* fix(node): complete auto-update integration and settings defaults

Capture the launcher in compiled test runtimes and trusted wrapper inventories, register the package update proof, and use the canonical Kysely read path. Preserve the inherited enabled state in the config UI and align caller tests with the node shutdown lifecycle.

* fix(node): preserve retained plugin work during automatic updates

Require an explicit idle result from plugin commands, preserve older-plugin work, and connect bundled lifetime owners to automatic node updates. Join canceled inference and failed terminal cleanup before command settlement; keep historical state repair with Doctor. Document compatibility and extend installed-package proof for retained legacy plugin work.

* test(browser): align idle-work fixtures with runtime exports

* test(browser): extract proxy request fixtures

* test(node): retain idle assertions across native cleanup
2026-09-18 06:20:27 -07:00

32 lines
1.2 KiB
TypeScript

import { expect, it, vi } from "vitest";
const cleanupMocks = vi.hoisted(() => ({
ensureBrowserProxyUploadCleanup: vi.fn(async () => undefined),
hasBrowserProxyUploadWork: vi.fn(() => false),
}));
vi.mock("./register.runtime.js", () => {
throw new Error("node-host availability must not load the broad browser runtime");
});
vi.mock("./src/browser-proxy-upload-cleanup.runtime.js", () => ({
ensureBrowserProxyUploadCleanup: cleanupMocks.ensureBrowserProxyUploadCleanup,
hasBrowserProxyUploadWork: cleanupMocks.hasBrowserProxyUploadWork,
}));
const { browserPluginNodeHostCommands } = await import("./plugin-registration.js");
it("starts node-host upload cleanup without loading the broad browser runtime", async () => {
const uploadCommand = browserPluginNodeHostCommands.find(
(command) => command.command === "browser.proxy.upload.v1",
);
expect(uploadCommand?.hasActiveWork?.()).toBe(false);
uploadCommand?.watchAvailability?.({ config: {}, env: {} }, vi.fn());
expect(uploadCommand?.hasActiveWork?.()).toBe(true);
await vi.waitFor(() => {
expect(cleanupMocks.ensureBrowserProxyUploadCleanup).toHaveBeenCalledOnce();
});
expect(uploadCommand?.hasActiveWork?.()).toBe(false);
});