@uniflow/plugin-sdk/testing 的 createTestHost 是一个内存里的迷你宿主:你的插件代码经与应用相同的运行时与消息协议执行
(结构化复制、错误还原、调用结束后能力作废都一样),宿主一侧按应用的规则实现:参数按 schema 校验、权限裁剪、read 模式只读、
模型来源的写命令先 describe 再确认、撤销栈、日历只能改自己的事件、存储的名字规则与 64KB 上限。
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { createTestHost } from '@uniflow/plugin-sdk/testing'
import plugin from '../src/main'
import pluginJson from '../plugin.json'
import en from '../locales/en.json'
test('snooze 可以撤销', async () => {
const host = createTestHost({
pluginJson, definition: plugin, locales: { en },
courses: [{ id: 'c1', name: 'Biology', code: 'BIO 101' }],
assignments: [/* PluginAssignment */],
events: [/* 用户自己的日历事件 */],
fetch: { 'https://api.example.com/x': 'body' }, // network 权限的假下载
openFile: () => ({ name: 'a.csv', text: 'q,a' }), // files.open 的假对话框
confirm: (description) => true, // 模型来源写命令的确认
})
const r = await host.run('snooze', { assignmentId: 'a1' }, { source: 'agent' })
assert.equal(r.ok, true)
assert.deepEqual(host.confirmations, ['把「Lab 3」隐藏到 …'])
assert.equal((await host.undo()).ok, true)
assert.deepEqual(host.storage(), { snoozed: {} })
})| host 上的 | 说明 |
|---|---|
run(action, args, { source }) |
source: 'ui'(默认,界面)/ 'agent'(模型:写命令先确认、agentVisible:false 的命令调不到) |
undo() |
撤销最近一次可撤销的写命令 |
storage() / deviceStorage() |
存储的快照 { 集合: { id: data } } |
events() |
日历事件快照 |
confirmations / saved / panels |
确认卡片文字 / files.save 写了什么 / openPanel 的参数 |
setLocale(lang)、t |
切换语言、取文案 |
测什么:每个命令至少覆盖正常路径、参数错误、前置条件错误(describe 里就拒绝)、撤销;纯计算逻辑抽成纯函数单独测
(模板里的 src/sessions.ts、src/due.ts)。迷你宿主是应用的忠实缩影但不是应用本身:发布前在应用里(开发者模式)走一遍。