import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { after, before, test } from "node:test"; import React, { createElement } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { createServer } from "vite"; let server; let DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY; let DevicePluginHostProvider; let commitPersistedDeviceModelId; let restorePersistedDeviceModelId; const hostSourceUrl = new URL( "../src/core/device-plugins/DevicePluginHost.tsx", import.meta.url, ); before(async () => { server = await createServer({ appType: "custom", logLevel: "silent", server: { middlewareMode: true }, }); ({ DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY, DevicePluginHostProvider, commitPersistedDeviceModelId, restorePersistedDeviceModelId, } = await server.ssrLoadModule("/src/core/device-plugins/DevicePluginHost.tsx")); }); after(async () => { await server?.close(); }); function memoryStorage(seed = {}) { const values = new Map(Object.entries(seed)); const calls = []; return { calls, getItem(key) { calls.push(["get", key]); return values.get(key) ?? null; }, setItem(key, value) { calls.push(["set", key, value]); values.set(key, value); }, removeItem(key) { calls.push(["remove", key]); values.delete(key); }, value(key) { return values.get(key) ?? null; }, }; } function registryWith(...modelIds) { const registered = new Set(modelIds); return { resolveModel(modelId) { return registered.has(modelId) ? { model: { id: modelId } } : null; }, }; } function fakePlugin(modelId) { function RuntimeProvider({ activeModel, children }) { return createElement( "div", { "data-active-model": activeModel?.id ?? "" }, children, ); } function ConnectionView() { return null; } return { manifest: { apiVersion: "missioncore.nodedc/v1alpha1", kind: "DevicePlugin", metadata: { id: "test.device.plugin", version: "1.0.0", displayName: "Test device", }, spec: { hostApiRange: "v1alpha1", runtime: { backendEntrypoint: "test.device:plugin", isolation: "transitional-in-process", }, permissions: [], actions: [{ id: "state.read", mutating: false, secretFields: [] }], models: [{ id: modelId, vendor: "Test", displayName: "Test model", category: "test", description: "test", verified: true, capabilities: [], ui: { slot: "device.connection", componentKey: "test.connection", }, }], }, }, RuntimeProvider, connectionViews: { "test.connection": ConnectionView }, }; } test("persisted model restore admits only an id in the current plugin registry", () => { const key = DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY; const registry = registryWith("xgrids.lixelkity-k1"); const valid = memoryStorage({ [key]: " xgrids.lixelkity-k1 " }); assert.equal( restorePersistedDeviceModelId(registry, valid), "xgrids.lixelkity-k1", ); assert.equal(valid.calls.some(([operation]) => operation === "remove"), false); for (const staleValue of ["removed.model", " "]) { const stale = memoryStorage({ [key]: staleValue }); assert.equal(restorePersistedDeviceModelId(registry, stale), null); assert.equal(stale.value(key), null, "a stale model id must be cleared"); } assert.equal(restorePersistedDeviceModelId(registry, null), null); }); test("fresh provider mount immediately activates the registry-validated persisted model", () => { const modelId = "test.model.one"; const storage = memoryStorage({ [DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY]: modelId, }); const previousWindow = globalThis.window; globalThis.window = { localStorage: storage }; try { const markup = renderToStaticMarkup(createElement( DevicePluginHostProvider, { plugins: [fakePlugin(modelId)] }, createElement("span", null, "runtime child"), )); assert.match(markup, /data-active-model="test\.model\.one"/); } finally { if (previousWindow === undefined) delete globalThis.window; else globalThis.window = previousWindow; } }); test("successful selection commits and explicit clear removes the same durable key", () => { const storage = memoryStorage(); commitPersistedDeviceModelId("xgrids.lixelkity-k1", storage); assert.equal( storage.value(DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY), "xgrids.lixelkity-k1", ); commitPersistedDeviceModelId(null, storage); assert.equal(storage.value(DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY), null); assert.deepEqual( storage.calls.slice(-1)[0], ["remove", DEVICE_PLUGIN_SELECTED_MODEL_STORAGE_KEY], ); }); test("unavailable browser storage fails closed without blocking host state", () => { const denied = { getItem() { throw new Error("storage denied"); }, setItem() { throw new Error("storage denied"); }, removeItem() { throw new Error("storage denied"); }, }; assert.equal( restorePersistedDeviceModelId(registryWith("xgrids.lixelkity-k1"), denied), null, ); assert.doesNotThrow(() => commitPersistedDeviceModelId("xgrids.lixelkity-k1", denied) ); assert.doesNotThrow(() => commitPersistedDeviceModelId(null, denied)); }); test("host writes persistence only after plugin deactivation succeeds", () => { const source = readFileSync(hostSourceUrl, "utf8"); const failedDeactivation = source.indexOf("if (!(await deactivate()))"); const admittedState = source.indexOf("setSelectedModelId(nextModelId);"); const durableCommit = source.indexOf( "commitPersistedDeviceModelId(nextModelId, selectionStorage);", admittedState, ); assert.ok(failedDeactivation >= 0); assert.ok( failedDeactivation < admittedState && admittedState < durableCommit, "failed deactivation branches must return before in-memory and durable commit", ); assert.match( source, /if \(nextModelId === selectedModelId\) \{[\s\S]*?commitPersistedDeviceModelId\(nextModelId, selectionStorage\);[\s\S]*?return true;/, "explicit clear must remove stale persistence even from an already-empty host", ); assert.match( source, /useState\(\(\) =>\s*restorePersistedDeviceModelId\(registry, selectionStorage\)/, "a fresh provider mount must restore before runtime providers receive activeModel", ); });