@zhin.js/cli 1.0.13 → 1.0.15

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.
@@ -0,0 +1,232 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
2
+ import * as fs from 'fs-extra'
3
+ import * as path from 'path'
4
+ import { tmpdir } from 'os'
5
+ import { execSync } from 'child_process'
6
+
7
+ describe('CLI new command integration', () => {
8
+ let testDir: string
9
+ const cliPath = path.resolve(__dirname, '../lib/cli.js')
10
+
11
+ beforeEach(async () => {
12
+ testDir = path.join(tmpdir(), `zhin-cli-integration-${Date.now()}`)
13
+ await fs.ensureDir(testDir)
14
+ })
15
+
16
+ afterEach(async () => {
17
+ try {
18
+ await fs.remove(testDir)
19
+ } catch (error) {
20
+ // Ignore cleanup errors
21
+ }
22
+ })
23
+
24
+ it('should create normal plugin with all files', async () => {
25
+ const pluginName = 'test-normal-plugin'
26
+
27
+ try {
28
+ execSync(
29
+ `node "${cliPath}" new ${pluginName} --type normal --skip-install`,
30
+ {
31
+ cwd: testDir,
32
+ stdio: 'ignore',
33
+ timeout: 10000
34
+ }
35
+ )
36
+ } catch (error: any) {
37
+ // Command might exit with code 1 due to missing package.json, but files should be created
38
+ }
39
+
40
+ const pluginDir = path.join(testDir, 'plugins', pluginName)
41
+
42
+ // Check directory structure
43
+ expect(await fs.pathExists(pluginDir)).toBe(true)
44
+ expect(await fs.pathExists(path.join(pluginDir, 'src'))).toBe(true)
45
+ expect(await fs.pathExists(path.join(pluginDir, 'tests'))).toBe(true)
46
+ expect(await fs.pathExists(path.join(pluginDir, 'client'))).toBe(true)
47
+ expect(await fs.pathExists(path.join(pluginDir, 'lib'))).toBe(true)
48
+ expect(await fs.pathExists(path.join(pluginDir, 'dist'))).toBe(true)
49
+
50
+ // Check package.json
51
+ const packageJsonPath = path.join(pluginDir, 'package.json')
52
+ expect(await fs.pathExists(packageJsonPath)).toBe(true)
53
+ const packageJson = await fs.readJson(packageJsonPath)
54
+ expect(packageJson.name).toBe(`zhin.js-${pluginName}`)
55
+ expect(packageJson.scripts.test).toBe('vitest run')
56
+ expect(packageJson.scripts['test:watch']).toBe('vitest')
57
+ expect(packageJson.scripts['test:coverage']).toBe('vitest run --coverage')
58
+ expect(packageJson.devDependencies.vitest).toBe('latest')
59
+ expect(packageJson.devDependencies['@vitest/coverage-v8']).toBe('latest')
60
+
61
+ // Check tsconfig.json
62
+ const tsconfigPath = path.join(pluginDir, 'tsconfig.json')
63
+ expect(await fs.pathExists(tsconfigPath)).toBe(true)
64
+ const tsconfig = await fs.readJson(tsconfigPath)
65
+ expect(tsconfig.compilerOptions.target).toBe('ES2022')
66
+ expect(tsconfig.compilerOptions.module).toBe('ESNext')
67
+
68
+ // Check src/index.ts
69
+ const srcIndexPath = path.join(pluginDir, 'src', 'index.ts')
70
+ expect(await fs.pathExists(srcIndexPath)).toBe(true)
71
+ const srcIndex = await fs.readFile(srcIndexPath, 'utf-8')
72
+ expect(srcIndex).toContain('useLogger')
73
+ expect(srcIndex).toContain('useContext')
74
+
75
+ // Check tests/index.test.ts
76
+ const testFilePath = path.join(pluginDir, 'tests', 'index.test.ts')
77
+ expect(await fs.pathExists(testFilePath)).toBe(true)
78
+ const testFile = await fs.readFile(testFilePath, 'utf-8')
79
+ expect(testFile).toContain('describe')
80
+ expect(testFile).toContain('Plugin Instance')
81
+ expect(testFile).toContain('Plugin Lifecycle')
82
+ expect(testFile).toContain('Plugin Features')
83
+ expect(testFile).toContain('Custom Tests')
84
+ expect(testFile).toContain('@zhin.js/core')
85
+
86
+ // Check README.md
87
+ const readmePath = path.join(pluginDir, 'README.md')
88
+ expect(await fs.pathExists(readmePath)).toBe(true)
89
+ const readme = await fs.readFile(readmePath, 'utf-8')
90
+ expect(readme).toContain(pluginName)
91
+
92
+ // Check .gitignore
93
+ const gitignorePath = path.join(pluginDir, '.gitignore')
94
+ expect(await fs.pathExists(gitignorePath)).toBe(true)
95
+ const gitignore = await fs.readFile(gitignorePath, 'utf-8')
96
+ expect(gitignore).toContain('node_modules/')
97
+ expect(gitignore).toContain('lib/')
98
+ expect(gitignore).toContain('dist/')
99
+
100
+ // Check CHANGELOG.md
101
+ const changelogPath = path.join(pluginDir, 'CHANGELOG.md')
102
+ expect(await fs.pathExists(changelogPath)).toBe(true)
103
+
104
+ // Check client files
105
+ const clientIndexPath = path.join(pluginDir, 'client', 'index.tsx')
106
+ expect(await fs.pathExists(clientIndexPath)).toBe(true)
107
+ const clientIndex = await fs.readFile(clientIndexPath, 'utf-8')
108
+ expect(clientIndex).toContain('addPage')
109
+ expect(clientIndex).toContain('@zhin.js/client')
110
+
111
+ const clientTsconfigPath = path.join(pluginDir, 'client', 'tsconfig.json')
112
+ expect(await fs.pathExists(clientTsconfigPath)).toBe(true)
113
+ }, 30000)
114
+
115
+ it('should create service plugin with service test template', async () => {
116
+ const serviceName = 'test-service'
117
+
118
+ try {
119
+ execSync(
120
+ `node "${cliPath}" new ${serviceName} --type service --skip-install`,
121
+ {
122
+ cwd: testDir,
123
+ stdio: 'ignore',
124
+ timeout: 10000
125
+ }
126
+ )
127
+ } catch (error: any) {
128
+ // Ignore exit code
129
+ }
130
+
131
+ const pluginDir = path.join(testDir, 'plugins', serviceName)
132
+ const testFilePath = path.join(pluginDir, 'tests', 'index.test.ts')
133
+
134
+ expect(await fs.pathExists(testFilePath)).toBe(true)
135
+ const testFile = await fs.readFile(testFilePath, 'utf-8')
136
+
137
+ // Service test should have TODO comments
138
+ expect(testFile).toContain('TODO')
139
+ expect(testFile).toContain('Service Instance')
140
+ expect(testFile).toContain('Service Methods')
141
+ expect(testFile).toContain('Service Lifecycle')
142
+ expect(testFile).toContain('Service Dependencies')
143
+ expect(testFile).toContain('Custom Tests')
144
+ }, 30000)
145
+
146
+ it('should create adapter plugin with adapter test template', async () => {
147
+ const adapterName = 'test-adapter'
148
+
149
+ try {
150
+ execSync(
151
+ `node "${cliPath}" new ${adapterName} --type adapter --skip-install`,
152
+ {
153
+ cwd: testDir,
154
+ stdio: 'ignore',
155
+ timeout: 10000
156
+ }
157
+ )
158
+ } catch (error: any) {
159
+ // Ignore exit code
160
+ }
161
+
162
+ const pluginDir = path.join(testDir, 'plugins', adapterName)
163
+ const testFilePath = path.join(pluginDir, 'tests', 'index.test.ts')
164
+
165
+ expect(await fs.pathExists(testFilePath)).toBe(true)
166
+ const testFile = await fs.readFile(testFilePath, 'utf-8')
167
+
168
+ // Adapter test should have Mock classes
169
+ expect(testFile).toContain('MockTestAdapterBot')
170
+ expect(testFile).toContain('MockTestAdapterAdapter')
171
+ expect(testFile).toContain('extends EventEmitter')
172
+ expect(testFile).toContain('extends Adapter')
173
+ expect(testFile).toContain('Adapter Instance')
174
+ expect(testFile).toContain('Bot Management')
175
+ expect(testFile).toContain('Adapter Lifecycle')
176
+ expect(testFile).toContain('Event Handling')
177
+ expect(testFile).toContain('Message Sending')
178
+ expect(testFile).toContain('Message Receiving')
179
+ expect(testFile).toContain('Bot Methods')
180
+ expect(testFile).toContain('Custom Tests')
181
+ }, 30000)
182
+
183
+ it('should create official plugin with @zhin.js scope', async () => {
184
+ const pluginName = 'official-plugin'
185
+
186
+ try {
187
+ execSync(
188
+ `node "${cliPath}" new ${pluginName} --type normal --is-official --skip-install`,
189
+ {
190
+ cwd: testDir,
191
+ stdio: 'ignore',
192
+ timeout: 10000
193
+ }
194
+ )
195
+ } catch (error: any) {
196
+ // Ignore exit code
197
+ }
198
+
199
+ const pluginDir = path.join(testDir, 'plugins', pluginName)
200
+ const packageJsonPath = path.join(pluginDir, 'package.json')
201
+
202
+ expect(await fs.pathExists(packageJsonPath)).toBe(true)
203
+ const packageJson = await fs.readJson(packageJsonPath)
204
+ expect(packageJson.name).toBe(`@zhin.js/${pluginName}`)
205
+ }, 30000)
206
+
207
+ it('should handle plugin name with hyphens', async () => {
208
+ const pluginName = 'my-awesome-plugin'
209
+
210
+ try {
211
+ execSync(
212
+ `node "${cliPath}" new ${pluginName} --type normal --skip-install`,
213
+ {
214
+ cwd: testDir,
215
+ stdio: 'ignore',
216
+ timeout: 10000
217
+ }
218
+ )
219
+ } catch (error: any) {
220
+ // Ignore exit code
221
+ }
222
+
223
+ const pluginDir = path.join(testDir, 'plugins', pluginName)
224
+ const srcIndexPath = path.join(pluginDir, 'src', 'index.ts')
225
+
226
+ expect(await fs.pathExists(srcIndexPath)).toBe(true)
227
+ const srcIndex = await fs.readFile(srcIndexPath, 'utf-8')
228
+
229
+ // Should convert to PascalCase: MyAwesomePlugin
230
+ expect(srcIndex).toContain('MyAwesomePlugin')
231
+ }, 30000)
232
+ })
@@ -0,0 +1,77 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest'
2
+ import * as fs from 'fs-extra'
3
+ import * as path from 'path'
4
+ import { tmpdir } from 'os'
5
+
6
+ describe('CLI Utils', () => {
7
+ describe('env utilities', () => {
8
+ let testDir: string
9
+
10
+ beforeEach(async () => {
11
+ testDir = path.join(tmpdir(), `zhin-test-${Date.now()}`)
12
+ await fs.ensureDir(testDir)
13
+ })
14
+
15
+ afterEach(async () => {
16
+ await fs.remove(testDir)
17
+ })
18
+
19
+ it('should export loadEnvFiles function', async () => {
20
+ const { loadEnvFiles } = await import('../src/utils/env')
21
+ expect(typeof loadEnvFiles).toBe('function')
22
+ })
23
+
24
+ it('should export getEnvLoadOrder function', async () => {
25
+ const { getEnvLoadOrder } = await import('../src/utils/env')
26
+ expect(typeof getEnvLoadOrder).toBe('function')
27
+ })
28
+
29
+ it('getEnvLoadOrder should return correct order', async () => {
30
+ const { getEnvLoadOrder } = await import('../src/utils/env')
31
+ const order = getEnvLoadOrder('development')
32
+ expect(order).toBeInstanceOf(Array)
33
+ expect(order.length).toBe(2)
34
+ expect(order[0]).toContain('.env')
35
+ expect(order[1]).toContain('development')
36
+ })
37
+
38
+ it('loadEnvFiles should not throw when no env files exist', async () => {
39
+ const { loadEnvFiles } = await import('../src/utils/env')
40
+ expect(() => loadEnvFiles(testDir, 'test')).not.toThrow()
41
+ })
42
+
43
+ it('loadEnvFiles should load env file if exists', async () => {
44
+ const { loadEnvFiles } = await import('../src/utils/env')
45
+ const envPath = path.join(testDir, '.env')
46
+ await fs.writeFile(envPath, 'TEST_VAR=test_value')
47
+
48
+ loadEnvFiles(testDir, 'test')
49
+ expect(process.env.TEST_VAR).toBe('test_value')
50
+
51
+ // 清理
52
+ delete process.env.TEST_VAR
53
+ })
54
+ })
55
+
56
+ describe('logger utilities', () => {
57
+ it('should export logger', async () => {
58
+ const { logger } = await import('../src/utils/logger')
59
+ expect(logger).toBeDefined()
60
+ expect(typeof logger).toBe('object')
61
+ })
62
+
63
+ it('logger should have log methods', async () => {
64
+ const { logger } = await import('../src/utils/logger')
65
+ expect(typeof logger.info).toBe('function')
66
+ expect(typeof logger.warn).toBe('function')
67
+ expect(typeof logger.error).toBe('function')
68
+ })
69
+ })
70
+
71
+ describe('process utilities', () => {
72
+ it('should export process utilities', async () => {
73
+ const processUtils = await import('../src/utils/process')
74
+ expect(processUtils).toBeDefined()
75
+ })
76
+ })
77
+ })