@zhin.js/core 1.0.57 → 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 (126) 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/ai/index.d.ts +2 -0
  6. package/lib/ai/index.d.ts.map +1 -1
  7. package/lib/ai/index.js +1 -0
  8. package/lib/ai/index.js.map +1 -1
  9. package/lib/built/adapter-process.d.ts +0 -4
  10. package/lib/built/adapter-process.d.ts.map +1 -1
  11. package/lib/built/adapter-process.js +0 -95
  12. package/lib/built/adapter-process.js.map +1 -1
  13. package/lib/built/agent-preset.d.ts +2 -0
  14. package/lib/built/agent-preset.d.ts.map +1 -1
  15. package/lib/built/agent-preset.js +4 -0
  16. package/lib/built/agent-preset.js.map +1 -1
  17. package/lib/built/command.d.ts +4 -0
  18. package/lib/built/command.d.ts.map +1 -1
  19. package/lib/built/command.js +6 -0
  20. package/lib/built/command.js.map +1 -1
  21. package/lib/built/component.d.ts.map +1 -1
  22. package/lib/built/component.js +1 -0
  23. package/lib/built/component.js.map +1 -1
  24. package/lib/built/dispatcher.d.ts.map +1 -1
  25. package/lib/built/dispatcher.js +0 -13
  26. package/lib/built/dispatcher.js.map +1 -1
  27. package/lib/built/message-filter.d.ts +2 -0
  28. package/lib/built/message-filter.d.ts.map +1 -1
  29. package/lib/built/message-filter.js +5 -0
  30. package/lib/built/message-filter.js.map +1 -1
  31. package/lib/built/skill.d.ts +11 -0
  32. package/lib/built/skill.d.ts.map +1 -1
  33. package/lib/built/skill.js +14 -0
  34. package/lib/built/skill.js.map +1 -1
  35. package/lib/built/tool.d.ts +11 -44
  36. package/lib/built/tool.d.ts.map +1 -1
  37. package/lib/built/tool.js +14 -353
  38. package/lib/built/tool.js.map +1 -1
  39. package/lib/plugin.d.ts +1 -25
  40. package/lib/plugin.d.ts.map +1 -1
  41. package/lib/plugin.js +1 -77
  42. package/lib/plugin.js.map +1 -1
  43. package/lib/types.d.ts +0 -25
  44. package/lib/types.d.ts.map +1 -1
  45. package/package.json +10 -7
  46. package/CHANGELOG.md +0 -538
  47. package/REFACTORING_COMPLETE.md +0 -178
  48. package/REFACTORING_STATUS.md +0 -263
  49. package/src/adapter.ts +0 -275
  50. package/src/ai/index.ts +0 -52
  51. package/src/ai/providers/anthropic.ts +0 -379
  52. package/src/ai/providers/base.ts +0 -175
  53. package/src/ai/providers/index.ts +0 -13
  54. package/src/ai/providers/ollama.ts +0 -302
  55. package/src/ai/providers/openai.ts +0 -174
  56. package/src/ai/types.ts +0 -348
  57. package/src/bot.ts +0 -37
  58. package/src/built/adapter-process.ts +0 -177
  59. package/src/built/agent-preset.ts +0 -136
  60. package/src/built/ai-trigger.ts +0 -259
  61. package/src/built/command.ts +0 -108
  62. package/src/built/common-adapter-tools.ts +0 -242
  63. package/src/built/component.ts +0 -130
  64. package/src/built/config.ts +0 -335
  65. package/src/built/cron.ts +0 -156
  66. package/src/built/database.ts +0 -134
  67. package/src/built/dispatcher.ts +0 -496
  68. package/src/built/login-assist.ts +0 -131
  69. package/src/built/message-filter.ts +0 -390
  70. package/src/built/permission.ts +0 -151
  71. package/src/built/schema-feature.ts +0 -190
  72. package/src/built/skill.ts +0 -221
  73. package/src/built/tool.ts +0 -948
  74. package/src/command.ts +0 -87
  75. package/src/component.ts +0 -565
  76. package/src/cron.ts +0 -4
  77. package/src/errors.ts +0 -46
  78. package/src/feature.ts +0 -7
  79. package/src/index.ts +0 -53
  80. package/src/jsx-dev-runtime.ts +0 -2
  81. package/src/jsx-runtime.ts +0 -12
  82. package/src/jsx.ts +0 -135
  83. package/src/message.ts +0 -48
  84. package/src/models/system-log.ts +0 -20
  85. package/src/models/user.ts +0 -15
  86. package/src/notice.ts +0 -98
  87. package/src/plugin.ts +0 -896
  88. package/src/prompt.ts +0 -293
  89. package/src/request.ts +0 -95
  90. package/src/scheduler/index.ts +0 -19
  91. package/src/scheduler/scheduler.ts +0 -372
  92. package/src/scheduler/types.ts +0 -74
  93. package/src/tool-zod.ts +0 -115
  94. package/src/types-generator.ts +0 -78
  95. package/src/types.ts +0 -505
  96. package/src/utils.ts +0 -227
  97. package/tests/adapter.test.ts +0 -638
  98. package/tests/ai/ai-trigger.test.ts +0 -368
  99. package/tests/ai/providers.integration.test.ts +0 -227
  100. package/tests/ai/setup.ts +0 -308
  101. package/tests/ai/tool.test.ts +0 -800
  102. package/tests/bot.test.ts +0 -151
  103. package/tests/command.test.ts +0 -737
  104. package/tests/component-new.test.ts +0 -361
  105. package/tests/config.test.ts +0 -372
  106. package/tests/cron.test.ts +0 -82
  107. package/tests/dispatcher.test.ts +0 -293
  108. package/tests/errors.test.ts +0 -21
  109. package/tests/expression-evaluation.test.ts +0 -258
  110. package/tests/features-builtin.test.ts +0 -191
  111. package/tests/jsx-runtime.test.ts +0 -45
  112. package/tests/jsx.test.ts +0 -319
  113. package/tests/message-filter.test.ts +0 -566
  114. package/tests/message.test.ts +0 -402
  115. package/tests/notice.test.ts +0 -198
  116. package/tests/plugin.test.ts +0 -779
  117. package/tests/prompt.test.ts +0 -78
  118. package/tests/redos-protection.test.ts +0 -198
  119. package/tests/request.test.ts +0 -221
  120. package/tests/schema.test.ts +0 -248
  121. package/tests/skill-feature.test.ts +0 -179
  122. package/tests/test-utils.ts +0 -59
  123. package/tests/tool-feature.test.ts +0 -254
  124. package/tests/types.test.ts +0 -162
  125. package/tests/utils.test.ts +0 -135
  126. 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
- })