netxops/test/client-settings-binding.test.mjs

107 lines
4.7 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { readFileSync, existsSync } from 'node:fs'
import { createRequire } from 'node:module'
import { homedir } from 'node:os'
import { join } from 'node:path'
import { runInNewContext } from 'node:vm'
import { Context, Service } from '@deepseek-ai/cordis'
const require = createRequire(import.meta.url)
// The shell seeds React from its own dependency tree, not the plugin's local
// development junction. Use that same installed peer tree for this built smoke.
const profileHome = process.env.DSH_HOME || join(homedir(), '.dsh')
const renderer = ['', 'desktop', 'web'].map(profile => join(profileHome, 'profiles', profile, 'node_modules',
'@deepseek-ai', 'dsh-client-ui-renderer', 'package.json')).find(existsSync)
const sharedRequire = renderer ? createRequire(renderer) : require
function loadClient() {
let client
runInNewContext(readFileSync(new URL('../lib/client.js', import.meta.url), 'utf8'), {
window: { __ModuleLoader__: { load({ factory }) { client = factory(spec =>
spec === 'react' || spec.startsWith('react/') ? sharedRequire(spec) : require(spec)) } } },
setTimeout, clearTimeout, setInterval, clearInterval, console, AbortController,
})
return client
}
const pause = ms => new Promise(resolve => setTimeout(resolve, ms))
function hostForm() {
let snapshot = { status: 'ready', writable: true, value: { toolsEnabled: true, groupOpsPresets: 'standard', apiUrl: 'http://127.0.0.1:8890' },
user: {}, base: {}, revision: 1 }
const listeners = new Set(), writes = []
return {
writes, getSnapshot: () => snapshot,
subscribe(fn) { listeners.add(fn); return () => listeners.delete(fn) },
async set(field, value) {
writes.push([field, value])
snapshot = { ...snapshot, value: { ...snapshot.value, [field]: value }, user: { ...snapshot.user, [field]: value }, revision: snapshot.revision + 1 }
for (const fn of listeners) fn()
return true
},
async unset(field) {
const user = { ...snapshot.user }; delete user[field]
snapshot = { ...snapshot, user, revision: snapshot.revision + 1 }
for (const fn of listeners) fn()
return true
},
}
}
async function fixture(t, legacy = false) {
const root = new Context(), owners = [], slots = new Map(), actual = hostForm()
class Slots extends Service {
constructor(ctx) { super(ctx, 'slots') }
inject(name, register) { return register() }
register(spec) {
const key = `${spec.name}:${spec.id ?? spec.key}`
slots.set(key, spec)
return () => slots.delete(key)
}
}
class Locale extends Service {
constructor(ctx) { super(ctx, 'locale') }
register() { return () => {} }
bind() { return key => key }
}
class Forms extends Service {
constructor(ctx) { super(ctx, legacy ? 'settingsScope' : 'configForms') }
get(id) { return id === 'netxops' ? actual : { getSnapshot: () => ({ status: 'unavailable', writable: false }) } }
bind({ namespace }) { return this.get(namespace) }
whileServed(ids, register) { return register(new Set(['netxops'])) }
}
t.after(async () => { for (const owner of owners.reverse()) await owner.dispose() })
for (const Provider of [Slots, Locale, Forms]) owners.push(await root.plugin(Provider))
const client = loadClient()
const owner = await root.plugin({ ...client, name: 'netxops-client-binding' })
owners.push(owner)
return { root, owner, slots, actual }
}
test('built settings card uses optional lookup in real Cordis and saves through the Host form', async t => {
const { owner, slots, actual } = await fixture(t)
assert.equal(owner.state, 2 /* ACTIVE */)
assert.throws(() => owner.ctx.configForms, /without inject/)
const section = slots.get('settings.section:dsh-netxops')
assert.ok(section)
const face = section.inject()
assert.equal(face.hooks.netxopsCard.getSnapshot().available, false)
await pause(80)
assert.equal(face.hooks.netxopsCard.getSnapshot().available, true)
assert.equal(face.hooks.netxopsCard.getSnapshot().writable, true)
assert.equal(face.hooks.netxopsCard.getSnapshot().groupOpsPresets.text, 'standard')
face.edit('toolsEnabled', 'false')
await pause(20)
assert.deepEqual(actual.writes, [['toolsEnabled', false]])
assert.equal(face.hooks.netxopsCard.getSnapshot().toolsEnabled.text, 'false')
assert.ok(slots.has('settings.plugin.item:netxops'))
})
test('built settings card still follows the legacy Host settings scope', async t => {
const { slots, actual } = await fixture(t, true)
const face = slots.get('settings.section:dsh-netxops').inject()
await pause(80)
assert.equal(face.hooks.netxopsCard.getSnapshot().available, true)
face.edit('groupOpsPresets', '')
await pause(20)
assert.deepEqual(actual.writes, [['groupOpsPresets', '']])
})