Skip to content

Commit 0fa24f0

Browse files
committed
feat:robot添加两组测试
1 parent 635bee1 commit 0fa24f0

4 files changed

Lines changed: 524 additions & 2 deletions

File tree

packages/plugins/robot/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
"access": "public"
66
},
77
"scripts": {
8-
"build": "vite build"
8+
"build": "vite build",
9+
"test": "vitest run",
10+
"test:watch": "vitest"
911
},
1012
"type": "module",
1113
"main": "dist/index.js",
@@ -45,7 +47,8 @@
4547
"@types/markdown-it": "^14.1.2",
4648
"@vitejs/plugin-vue": "^5.1.2",
4749
"@vitejs/plugin-vue-jsx": "^4.0.1",
48-
"vite": "^5.4.2"
50+
"vite": "^5.4.2",
51+
"vitest": "^1.6.1"
4952
},
5053
"peerDependencies": {
5154
"@opentiny/vue": "^3.20.0",
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest'
2+
3+
const canvasState = {
4+
pageSchema: null as any,
5+
saved: true,
6+
imported: [] as any[],
7+
history: [] as any[],
8+
published: [] as any[]
9+
}
10+
11+
vi.mock('@opentiny/tiny-engine-utils', () => ({
12+
utils: {
13+
deepClone: (value: unknown) => JSON.parse(JSON.stringify(value))
14+
}
15+
}))
16+
17+
vi.mock('@opentiny/vue-icon', () => ({
18+
default: {
19+
IconWarning: {}
20+
}
21+
}))
22+
23+
vi.mock('@opentiny/tiny-engine-meta-register', () => ({
24+
useCanvas: () => ({
25+
pageState: {
26+
get pageSchema() {
27+
return canvasState.pageSchema
28+
},
29+
set pageSchema(value) {
30+
canvasState.pageSchema = value
31+
}
32+
},
33+
importSchema: (schema: any) => {
34+
canvasState.imported.push(JSON.parse(JSON.stringify(schema)))
35+
canvasState.pageSchema = schema
36+
},
37+
setSaved: (saved: boolean) => {
38+
canvasState.saved = saved
39+
}
40+
}),
41+
useHistory: () => ({
42+
addHistory: () => {
43+
canvasState.history.push(JSON.parse(JSON.stringify(canvasState.pageSchema)))
44+
}
45+
}),
46+
useMessage: () => ({
47+
publish: (event: any) => {
48+
canvasState.published.push(event)
49+
}
50+
})
51+
}))
52+
53+
vi.mock('../../../src/composables/core/useConfig', () => ({
54+
default: () => ({
55+
getSelectedModelInfo: () => ({
56+
config: {
57+
chatMode: 'agent'
58+
}
59+
})
60+
})
61+
}))
62+
63+
const baseSchema = () => ({
64+
componentName: 'Page',
65+
props: {},
66+
state: {},
67+
methods: {},
68+
css: '',
69+
children: []
70+
})
71+
72+
const addButtonPatch = () =>
73+
JSON.stringify([
74+
{
75+
op: 'add',
76+
path: '/children/0',
77+
value: {
78+
componentName: 'TinyButton',
79+
props: {
80+
text: 'Submit'
81+
},
82+
children: []
83+
}
84+
}
85+
])
86+
87+
describe('pageUpdater', () => {
88+
beforeEach(async () => {
89+
vi.resetModules()
90+
canvasState.pageSchema = baseSchema()
91+
canvasState.saved = true
92+
canvasState.imported = []
93+
canvasState.history = []
94+
canvasState.published = []
95+
})
96+
97+
it('applies streaming updates without importing the whole schema', async () => {
98+
const { updatePageSchema } = await import('../../../src/composables/core/pageUpdater')
99+
const initialSchema = baseSchema()
100+
101+
const result = await updatePageSchema(addButtonPatch(), initialSchema, false)
102+
103+
expect(result?.schema?.children).toHaveLength(1)
104+
expect(canvasState.pageSchema.children).toHaveLength(1)
105+
expect(canvasState.pageSchema.children[0].componentName).toBe('TinyButton')
106+
expect(canvasState.imported).toHaveLength(0)
107+
expect(canvasState.history).toHaveLength(0)
108+
expect(canvasState.saved).toBe(false)
109+
expect(canvasState.published).toEqual([{ topic: 'schemaChange', data: {} }])
110+
})
111+
112+
it('imports and records history for final updates', async () => {
113+
const { updatePageSchema } = await import('../../../src/composables/core/pageUpdater')
114+
const initialSchema = baseSchema()
115+
116+
const result = await updatePageSchema(addButtonPatch(), initialSchema, true)
117+
118+
expect(result?.schema?.children).toHaveLength(1)
119+
expect(canvasState.imported).toHaveLength(1)
120+
expect(canvasState.imported[0].children[0].componentName).toBe('TinyButton')
121+
expect(canvasState.history).toHaveLength(1)
122+
expect(canvasState.published).toHaveLength(0)
123+
expect(canvasState.saved).toBe(false)
124+
})
125+
126+
it('stores the last successful streaming schema as a final fallback', async () => {
127+
const { getLastSuccessfulPageSchema, updatePageSchema } = await import('../../../src/composables/core/pageUpdater')
128+
const initialSchema = baseSchema()
129+
130+
await updatePageSchema(addButtonPatch(), initialSchema, false)
131+
const fallbackBeforeFinal = getLastSuccessfulPageSchema()
132+
const finalResult = await updatePageSchema('not json', initialSchema, true)
133+
134+
expect(finalResult?.isError).toBe(true)
135+
expect(getLastSuccessfulPageSchema()).toBe(fallbackBeforeFinal)
136+
expect(getLastSuccessfulPageSchema()?.children[0].componentName).toBe('TinyButton')
137+
})
138+
139+
it('clears the fallback only when a new agent turn starts', async () => {
140+
const { getLastSuccessfulPageSchema, resetPageSchemaUpdateState, updatePageSchema } = await import(
141+
'../../../src/composables/core/pageUpdater'
142+
)
143+
const initialSchema = baseSchema()
144+
145+
await updatePageSchema(addButtonPatch(), initialSchema, false)
146+
expect(getLastSuccessfulPageSchema()).toBeTruthy()
147+
148+
resetPageSchemaUpdateState()
149+
150+
expect(getLastSuccessfulPageSchema()).toBeNull()
151+
})
152+
153+
it('keeps the final schema after an earlier streaming update has completed', async () => {
154+
const { updatePageSchema } = await import('../../../src/composables/core/pageUpdater')
155+
const initialSchema = baseSchema()
156+
157+
const streamingResult = await updatePageSchema(addButtonPatch(), initialSchema, false)
158+
const finalResult = await updatePageSchema(
159+
JSON.stringify([
160+
{
161+
op: 'add',
162+
path: '/children/0',
163+
value: {
164+
componentName: 'TinyForm',
165+
props: {},
166+
children: []
167+
}
168+
}
169+
]),
170+
initialSchema,
171+
true
172+
)
173+
174+
expect(streamingResult?.schema?.children[0].componentName).toBe('TinyButton')
175+
expect(finalResult?.schema?.children[0].componentName).toBe('TinyForm')
176+
expect(canvasState.pageSchema.children[0].componentName).toBe('TinyForm')
177+
})
178+
179+
it('rejects schemas containing invalid children nodes before touching canvas', async () => {
180+
const { updatePageSchema } = await import('../../../src/composables/core/pageUpdater')
181+
const initialSchema = baseSchema()
182+
183+
const result = await updatePageSchema(
184+
JSON.stringify([
185+
{
186+
op: 'add',
187+
path: '/children/0',
188+
value: 'broken child'
189+
}
190+
]),
191+
initialSchema,
192+
true
193+
)
194+
195+
expect(result?.isError).toBe(true)
196+
expect(canvasState.imported).toHaveLength(0)
197+
expect(canvasState.pageSchema.children).toHaveLength(0)
198+
})
199+
200+
it('normalizes invalid methods before updating canvas', async () => {
201+
const { updatePageSchema } = await import('../../../src/composables/core/pageUpdater')
202+
const initialSchema = baseSchema()
203+
204+
const result = await updatePageSchema(
205+
JSON.stringify([
206+
{
207+
op: 'add',
208+
path: '/methods/submit',
209+
value: {
210+
type: 'JSExpression',
211+
value: 'this.submit()'
212+
}
213+
}
214+
]),
215+
initialSchema,
216+
true
217+
)
218+
219+
expect(result?.schema?.methods.submit.type).toBe('JSFunction')
220+
expect(result?.schema?.methods.submit.value).toContain('function submit()')
221+
expect(canvasState.pageSchema.methods.submit.type).toBe('JSFunction')
222+
})
223+
})

0 commit comments

Comments
 (0)