import assert from "node:assert/strict"; import { existsSync, readFileSync, readdirSync, statSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { dirname, join, resolve } from "node:path"; import { after, before, test } from "node:test"; import { createServer } from "vite"; const testRoot = dirname(fileURLToPath(import.meta.url)); const controlStationRoot = resolve(testRoot, ".."); const repositoryRoot = resolve(controlStationRoot, "../.."); const coreSourceRoot = join(controlStationRoot, "src"); const pluginFrontendRoot = join(repositoryRoot, "plugins/xgrids-k1/frontend/src"); const legacyPluginRoot = join(coreSourceRoot, "device-plugins/xgrids-k1"); function sourceFiles(root) { return readdirSync(root).flatMap((entry) => { const path = join(root, entry); if (statSync(path).isDirectory()) return sourceFiles(path); return /\.(?:css|ts|tsx)$/.test(entry) ? [path] : []; }); } let server; let createDevicePluginRegistry; before(async () => { server = await createServer({ appType: "custom", logLevel: "silent", server: { middlewareMode: true }, }); ({ createDevicePluginRegistry } = await server.ssrLoadModule( "/src/core/device-plugins/registry.ts", )); }); after(async () => { await server?.close(); }); function syntheticPlugin({ pluginId, modelId, componentKey, connectionView, spatialControlsView, }) { return { manifest: { apiVersion: "missioncore.nodedc/v1alpha2", kind: "DevicePlugin", metadata: { id: pluginId, version: "1.0.0", displayName: pluginId }, spec: { hostApiRange: "v1alpha2", runtime: { backendEntrypoint: `${pluginId}:build`, isolation: "transitional-in-process" }, permissions: ["device.read"], actions: [{ id: "state.read", mutating: false, secretFields: [] }], compatibilityProfiles: [{ profileId: `${modelId}.profile.v1`, path: `profiles/${modelId}.json`, modelId, }], models: [{ id: modelId, vendor: pluginId, displayName: modelId, category: "Sensor", description: "Synthetic frontend contribution", verified: true, capabilities: [{ id: "device.read", label: "Read" }], ui: { slot: "device.connection", componentKey }, }], }, }, RuntimeProvider: ({ children }) => children, connectionViews: { [componentKey]: connectionView }, ...(spatialControlsView ? { SpatialControlsView: spatialControlsView } : {}), }; } test("each device plugin contributes its own connection pipeline component", () => { const alphaConnection = () => null; const betaConnection = () => null; const registry = createDevicePluginRegistry([ syntheticPlugin({ pluginId: "synthetic.alpha", modelId: "synthetic.alpha.sensor", componentKey: "alpha.connection", connectionView: alphaConnection, }), syntheticPlugin({ pluginId: "synthetic.beta", modelId: "synthetic.beta.sensor", componentKey: "beta.connection", connectionView: betaConnection, }), ]); assert.equal(registry.resolveModel("synthetic.alpha.sensor").ConnectionView, alphaConnection); assert.equal(registry.resolveModel("synthetic.beta.sensor").ConnectionView, betaConnection); assert.notEqual( registry.resolveModel("synthetic.alpha.sensor").ConnectionView, registry.resolveModel("synthetic.beta.sensor").ConnectionView, ); }); test("selected-model shell leaves the model name to the connection heading", () => { const workspace = readFileSync( join(coreSourceRoot, "workspaces/DeviceWorkspace.tsx"), "utf8", ); const app = readFileSync(join(coreSourceRoot, "App.tsx"), "utf8"); const selectedSlot = workspace.slice(workspace.indexOf("const ConnectionView =")); assert.match(workspace, /