@zhin.js/core 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/lib/adapter.d.ts +1 -26
  2. package/lib/adapter.d.ts.map +1 -1
  3. package/lib/adapter.js +20 -117
  4. package/lib/adapter.js.map +1 -1
  5. package/lib/built/adapter-process.d.ts +0 -4
  6. package/lib/built/adapter-process.d.ts.map +1 -1
  7. package/lib/built/adapter-process.js +0 -95
  8. package/lib/built/adapter-process.js.map +1 -1
  9. package/lib/built/agent-preset.d.ts +2 -0
  10. package/lib/built/agent-preset.d.ts.map +1 -1
  11. package/lib/built/agent-preset.js +4 -0
  12. package/lib/built/agent-preset.js.map +1 -1
  13. package/lib/built/command.d.ts +4 -0
  14. package/lib/built/command.d.ts.map +1 -1
  15. package/lib/built/command.js +6 -0
  16. package/lib/built/command.js.map +1 -1
  17. package/lib/built/component.d.ts.map +1 -1
  18. package/lib/built/component.js +1 -0
  19. package/lib/built/component.js.map +1 -1
  20. package/lib/built/dispatcher.d.ts.map +1 -1
  21. package/lib/built/dispatcher.js +0 -13
  22. package/lib/built/dispatcher.js.map +1 -1
  23. package/lib/built/message-filter.d.ts +2 -0
  24. package/lib/built/message-filter.d.ts.map +1 -1
  25. package/lib/built/message-filter.js +5 -0
  26. package/lib/built/message-filter.js.map +1 -1
  27. package/lib/built/skill.d.ts +11 -0
  28. package/lib/built/skill.d.ts.map +1 -1
  29. package/lib/built/skill.js +14 -0
  30. package/lib/built/skill.js.map +1 -1
  31. package/lib/built/tool.d.ts +11 -44
  32. package/lib/built/tool.d.ts.map +1 -1
  33. package/lib/built/tool.js +14 -353
  34. package/lib/built/tool.js.map +1 -1
  35. package/lib/plugin.d.ts +1 -25
  36. package/lib/plugin.d.ts.map +1 -1
  37. package/lib/plugin.js +1 -77
  38. package/lib/plugin.js.map +1 -1
  39. package/lib/types.d.ts +0 -25
  40. package/lib/types.d.ts.map +1 -1
  41. package/package.json +10 -7
  42. package/CHANGELOG.md +0 -561
  43. package/REFACTORING_COMPLETE.md +0 -178
  44. package/REFACTORING_STATUS.md +0 -263
  45. package/src/adapter.ts +0 -275
  46. package/src/ai/index.ts +0 -55
  47. package/src/ai/providers/anthropic.ts +0 -379
  48. package/src/ai/providers/base.ts +0 -175
  49. package/src/ai/providers/index.ts +0 -13
  50. package/src/ai/providers/ollama.ts +0 -302
  51. package/src/ai/providers/openai.ts +0 -174
  52. package/src/ai/types.ts +0 -348
  53. package/src/bot.ts +0 -37
  54. package/src/built/adapter-process.ts +0 -177
  55. package/src/built/agent-preset.ts +0 -136
  56. package/src/built/ai-trigger.ts +0 -259
  57. package/src/built/command.ts +0 -108
  58. package/src/built/common-adapter-tools.ts +0 -242
  59. package/src/built/component.ts +0 -130
  60. package/src/built/config.ts +0 -335
  61. package/src/built/cron.ts +0 -156
  62. package/src/built/database.ts +0 -134
  63. package/src/built/dispatcher.ts +0 -496
  64. package/src/built/login-assist.ts +0 -131
  65. package/src/built/message-filter.ts +0 -390
  66. package/src/built/permission.ts +0 -151
  67. package/src/built/schema-feature.ts +0 -190
  68. package/src/built/skill.ts +0 -221
  69. package/src/built/tool.ts +0 -948
  70. package/src/command.ts +0 -87
  71. package/src/component.ts +0 -565
  72. package/src/cron.ts +0 -4
  73. package/src/errors.ts +0 -46
  74. package/src/feature.ts +0 -7
  75. package/src/index.ts +0 -53
  76. package/src/jsx-dev-runtime.ts +0 -2
  77. package/src/jsx-runtime.ts +0 -12
  78. package/src/jsx.ts +0 -135
  79. package/src/message.ts +0 -48
  80. package/src/models/system-log.ts +0 -20
  81. package/src/models/user.ts +0 -15
  82. package/src/notice.ts +0 -98
  83. package/src/plugin.ts +0 -896
  84. package/src/prompt.ts +0 -293
  85. package/src/request.ts +0 -95
  86. package/src/scheduler/index.ts +0 -19
  87. package/src/scheduler/scheduler.ts +0 -372
  88. package/src/scheduler/types.ts +0 -74
  89. package/src/tool-zod.ts +0 -115
  90. package/src/types-generator.ts +0 -78
  91. package/src/types.ts +0 -505
  92. package/src/utils.ts +0 -227
  93. package/tests/adapter.test.ts +0 -638
  94. package/tests/ai/ai-trigger.test.ts +0 -368
  95. package/tests/ai/providers.integration.test.ts +0 -227
  96. package/tests/ai/setup.ts +0 -308
  97. package/tests/ai/tool.test.ts +0 -800
  98. package/tests/bot.test.ts +0 -151
  99. package/tests/command.test.ts +0 -737
  100. package/tests/component-new.test.ts +0 -361
  101. package/tests/config.test.ts +0 -372
  102. package/tests/cron.test.ts +0 -82
  103. package/tests/dispatcher.test.ts +0 -293
  104. package/tests/errors.test.ts +0 -21
  105. package/tests/expression-evaluation.test.ts +0 -258
  106. package/tests/features-builtin.test.ts +0 -191
  107. package/tests/jsx-runtime.test.ts +0 -45
  108. package/tests/jsx.test.ts +0 -319
  109. package/tests/message-filter.test.ts +0 -566
  110. package/tests/message.test.ts +0 -402
  111. package/tests/notice.test.ts +0 -198
  112. package/tests/plugin.test.ts +0 -779
  113. package/tests/prompt.test.ts +0 -78
  114. package/tests/redos-protection.test.ts +0 -198
  115. package/tests/request.test.ts +0 -221
  116. package/tests/schema.test.ts +0 -248
  117. package/tests/skill-feature.test.ts +0 -179
  118. package/tests/test-utils.ts +0 -59
  119. package/tests/tool-feature.test.ts +0 -254
  120. package/tests/types.test.ts +0 -162
  121. package/tests/utils.test.ts +0 -135
  122. package/tsconfig.json +0 -24
@@ -1,191 +0,0 @@
1
- /**
2
- * 内置 Feature 测试
3
- * DatabaseFeature / PermissionFeature / ComponentFeature
4
- */
5
- import { describe, it, expect, beforeEach, vi } from 'vitest';
6
- import { PermissionFeature, Permissions } from '../src/built/permission.js';
7
- import { ComponentFeature } from '../src/built/component.js';
8
- import type { Message, MessageBase } from '../src/message.js';
9
-
10
- // ============================================================================
11
- // PermissionFeature 测试
12
- // ============================================================================
13
-
14
- describe('PermissionFeature', () => {
15
- let feature: PermissionFeature;
16
-
17
- beforeEach(() => {
18
- feature = new PermissionFeature();
19
- });
20
-
21
- function makeMessage(overrides: Partial<MessageBase> = {}): Message<any> {
22
- return {
23
- $id: '1',
24
- $adapter: 'test' as any,
25
- $bot: 'bot1',
26
- $content: [],
27
- $raw: '',
28
- $sender: { id: 'user1', name: 'User' },
29
- $channel: { id: 'ch1', type: 'group' },
30
- $timestamp: Date.now(),
31
- $reply: vi.fn(),
32
- $recall: vi.fn(),
33
- ...overrides,
34
- } as any;
35
- }
36
-
37
- it('应有正确的元数据', () => {
38
- expect(feature.name).toBe('permission');
39
- expect(feature.icon).toBe('Shield');
40
- expect(feature.desc).toBe('权限');
41
- });
42
-
43
- it('构造时应注册内置权限检查器', () => {
44
- // 构造时已注册 adapter(), group(), private(), channel(), user() 检查器
45
- expect(feature.items.length).toBeGreaterThanOrEqual(5);
46
- });
47
-
48
- describe('check', () => {
49
- it('adapter() 匹配应返回 true', async () => {
50
- const msg = makeMessage({ $adapter: 'qq' as any });
51
- expect(await feature.check('adapter(qq)', msg)).toBe(true);
52
- });
53
-
54
- it('adapter() 不匹配应返回 false', async () => {
55
- const msg = makeMessage({ $adapter: 'qq' as any });
56
- expect(await feature.check('adapter(discord)', msg)).toBe(false);
57
- });
58
-
59
- it('group() 匹配应返回 true', async () => {
60
- const msg = makeMessage({ $channel: { id: 'g1', type: 'group' } });
61
- expect(await feature.check('group(g1)', msg)).toBe(true);
62
- });
63
-
64
- it('group(*) 通配应返回 true', async () => {
65
- const msg = makeMessage({ $channel: { id: 'g123', type: 'group' } });
66
- expect(await feature.check('group(*)', msg)).toBe(true);
67
- });
68
-
69
- it('private() 匹配应返回 true', async () => {
70
- const msg = makeMessage({ $channel: { id: 'p1', type: 'private' } });
71
- expect(await feature.check('private(p1)', msg)).toBe(true);
72
- });
73
-
74
- it('user() 匹配应返回 true', async () => {
75
- const msg = makeMessage({ $sender: { id: 'u1', name: 'U' } });
76
- expect(await feature.check('user(u1)', msg)).toBe(true);
77
- });
78
-
79
- it('user() 不匹配应返回 false', async () => {
80
- const msg = makeMessage({ $sender: { id: 'u1', name: 'U' } });
81
- expect(await feature.check('user(u2)', msg)).toBe(false);
82
- });
83
-
84
- it('未注册的权限名应返回 false', async () => {
85
- const msg = makeMessage();
86
- expect(await feature.check('unknown_permission', msg)).toBe(false);
87
- });
88
- });
89
-
90
- describe('自定义权限', () => {
91
- it('应能添加自定义权限检查器', async () => {
92
- const perm = Permissions.define('admin', (_name, msg) => {
93
- return msg.$sender.id === 'admin_user';
94
- });
95
-
96
- feature.add(perm, 'test-plugin');
97
-
98
- const adminMsg = makeMessage({ $sender: { id: 'admin_user', name: 'Admin' } });
99
- const normalMsg = makeMessage({ $sender: { id: 'normal_user', name: 'Normal' } });
100
-
101
- expect(await feature.check('admin', adminMsg)).toBe(true);
102
- expect(await feature.check('admin', normalMsg)).toBe(false);
103
- });
104
- });
105
-
106
- describe('toJSON', () => {
107
- it('应序列化所有权限', () => {
108
- const json = feature.toJSON();
109
- expect(json.name).toBe('permission');
110
- expect(json.count).toBeGreaterThan(0);
111
- });
112
-
113
- it('应按插件名过滤', () => {
114
- feature.add(Permissions.define('custom', () => true), 'my-plugin');
115
- const json = feature.toJSON('my-plugin');
116
- expect(json.count).toBe(1);
117
- });
118
- });
119
- });
120
-
121
- // ============================================================================
122
- // ComponentFeature 测试
123
- // ============================================================================
124
-
125
- describe('ComponentFeature', () => {
126
- let feature: ComponentFeature;
127
-
128
- beforeEach(() => {
129
- feature = new ComponentFeature();
130
- });
131
-
132
- const mockComponent = {
133
- name: 'test-component',
134
- render: () => ({ type: 'text', data: { text: 'test' } }),
135
- } as any;
136
-
137
- it('应有正确的元数据', () => {
138
- expect(feature.name).toBe('component');
139
- expect(feature.icon).toBe('Box');
140
- expect(feature.desc).toBe('组件');
141
- });
142
-
143
- it('add 应添加组件', () => {
144
- feature.add(mockComponent, 'test-plugin');
145
- expect(feature.items).toHaveLength(1);
146
- expect(feature.byName.get('test-component')).toBe(mockComponent);
147
- });
148
-
149
- it('remove 应移除组件', () => {
150
- feature.add(mockComponent, 'test-plugin');
151
- feature.remove(mockComponent);
152
- expect(feature.items).toHaveLength(0);
153
- expect(feature.byName.has('test-component')).toBe(false);
154
- });
155
-
156
- it('get 应按名称获取', () => {
157
- feature.add(mockComponent, 'test-plugin');
158
- expect(feature.get('test-component')).toBe(mockComponent);
159
- expect(feature.get('nonexistent')).toBeUndefined();
160
- });
161
-
162
- it('getAllNames 应返回所有名称', () => {
163
- feature.add(mockComponent, 'test-plugin');
164
- feature.add({ name: 'another', render: () => null } as any, 'test-plugin');
165
- expect(feature.getAllNames()).toEqual(['test-component', 'another']);
166
- });
167
-
168
- describe('toJSON', () => {
169
- it('应返回正确结构', () => {
170
- feature.add(mockComponent, 'test-plugin');
171
- const json = feature.toJSON();
172
- expect(json.name).toBe('component');
173
- expect(json.count).toBe(1);
174
- expect(json.items[0]).toEqual({ name: 'test-component', type: 'component' });
175
- });
176
-
177
- it('按插件名过滤', () => {
178
- feature.add(mockComponent, 'plugin-a');
179
- feature.add({ name: 'other', render: () => null } as any, 'plugin-b');
180
- const json = feature.toJSON('plugin-a');
181
- expect(json.count).toBe(1);
182
- });
183
- });
184
- });
185
-
186
- // ============================================================================
187
- // DatabaseFeature 说明
188
- // ============================================================================
189
- // DatabaseFeature 需要实际数据库连接(sqlite3 等),测试跳过。
190
- // 其核心逻辑(add/remove/toJSON)已由 Feature 基类测试覆盖。
191
- // 数据库相关测试见 basic/database/ 目录。
@@ -1,45 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import * as jsxRuntime from '../src/jsx-runtime'
3
- import * as jsxDevRuntime from '../src/jsx-dev-runtime'
4
-
5
- describe('JSX Runtime', () => {
6
- it('should export jsx function', () => {
7
- expect(typeof jsxRuntime.jsx).toBe('function')
8
- })
9
-
10
- it('should export jsxs function', () => {
11
- expect(typeof jsxRuntime.jsxs).toBe('function')
12
- })
13
-
14
- it('should export Fragment', () => {
15
- expect(jsxRuntime.Fragment).toBeDefined()
16
- })
17
-
18
- it('should export renderJSX function', () => {
19
- expect(typeof jsxRuntime.renderJSX).toBe('function')
20
- })
21
-
22
- it('should have default export', () => {
23
- expect(jsxRuntime.default).toBeDefined()
24
- expect(typeof jsxRuntime.default.jsx).toBe('function')
25
- expect(typeof jsxRuntime.default.jsxs).toBe('function')
26
- })
27
- })
28
-
29
- describe('JSX Dev Runtime', () => {
30
- it('should export jsx function', () => {
31
- expect(typeof jsxDevRuntime.jsx).toBe('function')
32
- })
33
-
34
- it('should export jsxDEV function', () => {
35
- expect(typeof jsxDevRuntime.jsxDEV).toBe('function')
36
- })
37
-
38
- it('should export Fragment', () => {
39
- expect(jsxDevRuntime.Fragment).toBeDefined()
40
- })
41
-
42
- it('should export renderJSX function', () => {
43
- expect(typeof jsxDevRuntime.renderJSX).toBe('function')
44
- })
45
- })
package/tests/jsx.test.ts DELETED
@@ -1,319 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest'
2
- import { jsx, jsxs, Fragment, renderJSX } from '../src/jsx'
3
- import { Component, ComponentContext } from '../src/component'
4
- import { MessageComponent } from '../src/message'
5
-
6
- describe('JSX消息组件系统测试', () => {
7
- let mockContext: ComponentContext
8
-
9
- beforeEach(() => {
10
- mockContext = {
11
- event: {
12
- $id: 'test-msg',
13
- $adapter: 'test',
14
- $bot: 'test-bot',
15
- $content: [],
16
- $sender: { id: 'user123', name: 'testuser' },
17
- $reply: vi.fn().mockResolvedValue('reply123'),
18
- $channel: { id: 'channel123', type: 'group' },
19
- $timestamp: Date.now(),
20
- $raw: 'test message'
21
- }
22
- } as any
23
- })
24
-
25
- describe('JSX元素创建', () => {
26
- it('应该创建基础JSX元素', () => {
27
- const element = jsx('text', { children: 'Hello World' })
28
-
29
- expect(element).toEqual({
30
- type: 'text',
31
- data: { children: 'Hello World' }
32
- })
33
- })
34
-
35
- it('应该创建带属性的JSX元素', () => {
36
- const element = jsx('image', {
37
- src: 'https://example.com/image.jpg',
38
- alt: '测试图片',
39
- children: null
40
- })
41
-
42
- expect(element).toEqual({
43
- type: 'image',
44
- data: {
45
- src: 'https://example.com/image.jpg',
46
- alt: '测试图片',
47
- children: null
48
- }
49
- })
50
- })
51
-
52
- it('应该创建嵌套JSX元素', () => {
53
- const child = jsx('text', { children: '内容' })
54
- const parent = jsx('div', { children: [child] })
55
-
56
- expect(parent.data.children).toContain(child)
57
- })
58
-
59
- it('jsxs应该与jsx功能相同', () => {
60
- const element1 = jsx('text', { children: 'Hello' })
61
- const element2 = jsxs('text', { children: 'Hello' })
62
-
63
- expect(element1).toEqual(element2)
64
- })
65
- })
66
-
67
- describe('Fragment组件', () => {
68
- it('应该支持Fragment', () => {
69
- const fragment = jsx(Fragment, {
70
- children: ['Hello', ' ', 'World']
71
- })
72
-
73
- expect(fragment.type).toBe(Fragment)
74
- expect(fragment.data.children).toEqual(['Hello', ' ', 'World'])
75
- })
76
-
77
- it('Fragment应该是函数类型', () => {
78
- expect(typeof Fragment).toBe('function')
79
- expect(Fragment.name).toBe('Fragment')
80
- })
81
- })
82
-
83
- describe('JSX渲染', () => {
84
- it('应该渲染纯文本元素', async () => {
85
- const element = jsx('text', { children: 'Hello World' })
86
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
87
-
88
- expect(result).toBe('Hello World')
89
- })
90
-
91
- it('应该渲染Fragment', async () => {
92
- const fragment = jsx('Fragment', {
93
- children: ['Hello', ' ', 'World']
94
- })
95
- const result = await renderJSX(fragment as MessageComponent<any>, mockContext)
96
-
97
- expect(result).toBe('Hello World')
98
- })
99
-
100
- it('应该渲染嵌套元素', async () => {
101
- const nested = jsx('div', {
102
- children: [
103
- jsx('text', { children: 'Hello' }),
104
- ' ',
105
- jsx('text', { children: 'World' })
106
- ]
107
- })
108
- const result = await renderJSX(nested as MessageComponent<any>, mockContext)
109
-
110
- expect(result).toBe('Hello World')
111
- })
112
-
113
- it('应该处理null和undefined子元素', async () => {
114
- const element = jsx('div', {
115
- children: [null, undefined, 'Hello', null, 'World', undefined]
116
- })
117
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
118
-
119
- expect(result).toBe('HelloWorld')
120
- })
121
-
122
- it('应该处理数字和布尔值', async () => {
123
- const element = jsx('div', {
124
- children: [42, true, false, 'text']
125
- })
126
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
127
-
128
- expect(result).toBe('42truefalsetext')
129
- })
130
- })
131
-
132
- describe('函数组件', () => {
133
- it('应该渲染函数组件', async () => {
134
- const TestComponent: Component<{ name: string }> = async (props, context) => {
135
- return `Hello, ${props.name}!`
136
- }
137
-
138
- const element = jsx(TestComponent, { name: '用户' })
139
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
140
-
141
- expect(result).toBe('Hello, 用户!')
142
- })
143
-
144
- it('应该向函数组件传递context', async () => {
145
- const ContextComponent: Component<{}> = async (props, context) => {
146
- return `Root: ${context?.root || 'No Root'}`
147
- }
148
-
149
- const element = jsx(ContextComponent, {})
150
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
151
-
152
- expect(result).toContain('Root:')
153
- })
154
-
155
- it('应该处理异步函数组件', async () => {
156
- const AsyncComponent: Component<{ delay: number }> = async (props) => {
157
- await new Promise(resolve => setTimeout(resolve, props.delay))
158
- return 'Async content'
159
- }
160
-
161
- const element = jsx(AsyncComponent, { delay: 10 })
162
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
163
-
164
- expect(result).toBe('Async content')
165
- })
166
-
167
- it('应该支持组件返回JSX元素', async () => {
168
- const WrapperComponent: Component<{ text: string }> = async (props) => {
169
- return `Wrapped: ${props.text}`
170
- }
171
-
172
- const element = jsx(WrapperComponent, { text: 'content' })
173
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
174
-
175
- // 由于函数组件返回字符串
176
- expect(result).toBe('Wrapped: content')
177
- })
178
- })
179
-
180
- describe('复杂渲染场景', () => {
181
- it('应该处理深度嵌套', async () => {
182
- const DeepComponent: Component<{ level: number }> = async (props) => {
183
- if (props.level <= 0) return `Level ${props.level}`
184
- return `Nested Level ${props.level}`
185
- }
186
-
187
- const element = jsx(DeepComponent, { level: 3 })
188
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
189
-
190
- expect(result).toBe('Nested Level 3')
191
- })
192
-
193
- it('应该处理组件数组', async () => {
194
- const Item: Component<{ text: string }> = async (props) => `[${props.text}]`
195
-
196
- const items = ['A', 'B', 'C'].map(text => jsx(Item, { text }))
197
- const container = jsx('div', { children: items })
198
-
199
- const result = await renderJSX(container as MessageComponent<any>, mockContext)
200
-
201
- expect(result).toBe('[A][B][C]')
202
- })
203
-
204
- it('应该处理条件渲染', async () => {
205
- const ConditionalComponent: Component<{ show: boolean; text: string }> = async (props) => {
206
- return props.show ? props.text : ''
207
- }
208
-
209
- const element1 = jsx(ConditionalComponent, { show: true, text: 'Visible' })
210
- const element2 = jsx(ConditionalComponent, { show: false, text: 'Hidden' })
211
-
212
- const result1 = await renderJSX(element1 as MessageComponent<any>, mockContext)
213
- const result2 = await renderJSX(element2 as MessageComponent<any>, mockContext)
214
-
215
- expect(result1).toBe('Visible')
216
- expect(result2).toBe('')
217
- })
218
- })
219
-
220
- describe('错误处理', () => {
221
- it('应该捕获组件执行错误并返回错误消息', async () => {
222
- const ErrorComponent: Component<{}> = async () => {
223
- throw new Error('Component error')
224
- }
225
-
226
- const element = jsx(ErrorComponent, {})
227
-
228
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
229
- expect(result).toBe('❌ 组件渲染失败: Component error')
230
- })
231
-
232
- it('应该处理无效的元素类型', async () => {
233
- const invalidElement = {
234
- type: 123 as any, // 无效类型
235
- data: { children: 'test' }
236
- }
237
-
238
- const result = await renderJSX(invalidElement as MessageComponent<any>, mockContext)
239
- expect(result).toMatch(/❌ 组件渲染失败/)
240
- })
241
-
242
- it('应该处理异步组件返回 Promise 的情况', async () => {
243
- const AsyncPromiseComponent: Component<{ text: string }> = async (props) => {
244
- // 返回一个 Promise(会被自动 await)
245
- return Promise.resolve(`Async: ${props.text}`)
246
- }
247
-
248
- const element = jsx(AsyncPromiseComponent, { text: 'test' })
249
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
250
-
251
- expect(result).toBe('Async: test')
252
- })
253
-
254
- it('应该处理子组件为 Promise 的情况', async () => {
255
- const AsyncChild = Promise.resolve('Async Child Content')
256
- const element = jsx('div', { children: [AsyncChild] })
257
-
258
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
259
- expect(result).toBe('Async Child Content')
260
- })
261
- })
262
-
263
- describe('性能和内存', () => {
264
- it('应该处理大量子元素', async () => {
265
- const manyChildren = Array.from({ length: 100 }, (_, i) => `Item ${i}`)
266
- const element = jsx('div', { children: manyChildren })
267
-
268
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
269
-
270
- expect(result).toContain('Item 0')
271
- expect(result).toContain('Item 99')
272
- expect(typeof result).toBe('string')
273
- })
274
-
275
- it('应该正确处理空子元素数组', async () => {
276
- const element = jsx('div', { children: [] })
277
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
278
-
279
- expect(result).toBe('')
280
- })
281
- })
282
-
283
- describe('类型安全', () => {
284
- it('应该正确处理各种数据类型', async () => {
285
- const element = jsx('div', {
286
- children: [
287
- 'string',
288
- 42,
289
- true,
290
- false,
291
- null,
292
- undefined,
293
- jsx('span', { children: 'nested' })
294
- ]
295
- })
296
-
297
- const result = await renderJSX(element as MessageComponent<any>, mockContext)
298
-
299
- expect(result).toBe('string42truefalsenested')
300
- })
301
-
302
- it('应该保持属性数据完整性', () => {
303
- const props = {
304
- id: 'test-id',
305
- className: 'test-class',
306
- onClick: () => {},
307
- data: { key: 'value' },
308
- children: 'content'
309
- }
310
-
311
- const element = jsx('button', props)
312
-
313
- expect(element.data).toEqual(props)
314
- expect(element.data.id).toBe('test-id')
315
- expect(element.data.className).toBe('test-class')
316
- expect(typeof element.data.onClick).toBe('function')
317
- })
318
- })
319
- })