@codeguide/core 0.0.1
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.
- package/__tests__/authentication.test.ts +259 -0
- package/__tests__/codeguide.test.ts +293 -0
- package/__tests__/services/base/base-service.test.ts +334 -0
- package/__tests__/services/generation/generation-service.test.ts +294 -0
- package/__tests__/services/usage/usage-service.test.ts +385 -0
- package/__tests__/simple.test.ts +10 -0
- package/__tests__/test-service.ts +37 -0
- package/api-service.ts +67 -0
- package/codeguide.ts +70 -0
- package/dist/__tests__/test-service.d.ts +12 -0
- package/dist/__tests__/test-service.js +32 -0
- package/dist/api-service.d.ts +8 -0
- package/dist/api-service.js +64 -0
- package/dist/codeguide.d.ts +14 -0
- package/dist/codeguide.js +53 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +31 -0
- package/dist/services/base/base-service.d.ts +30 -0
- package/dist/services/base/base-service.js +187 -0
- package/dist/services/base/index.d.ts +1 -0
- package/dist/services/base/index.js +5 -0
- package/dist/services/generation/generation-service.d.ts +15 -0
- package/dist/services/generation/generation-service.js +40 -0
- package/dist/services/generation/generation-types.d.ts +111 -0
- package/dist/services/generation/generation-types.js +2 -0
- package/dist/services/generation/index.d.ts +2 -0
- package/dist/services/generation/index.js +20 -0
- package/dist/services/index.d.ts +11 -0
- package/dist/services/index.js +45 -0
- package/dist/services/projects/index.d.ts +2 -0
- package/dist/services/projects/index.js +20 -0
- package/dist/services/projects/project-service.d.ts +14 -0
- package/dist/services/projects/project-service.js +53 -0
- package/dist/services/projects/project-types.d.ts +97 -0
- package/dist/services/projects/project-types.js +2 -0
- package/dist/services/repository-analysis/index.d.ts +2 -0
- package/dist/services/repository-analysis/index.js +20 -0
- package/dist/services/repository-analysis/repository-service.d.ts +10 -0
- package/dist/services/repository-analysis/repository-service.js +31 -0
- package/dist/services/repository-analysis/repository-types.d.ts +90 -0
- package/dist/services/repository-analysis/repository-types.js +2 -0
- package/dist/services/tasks/index.d.ts +2 -0
- package/dist/services/tasks/index.js +20 -0
- package/dist/services/tasks/task-service.d.ts +30 -0
- package/dist/services/tasks/task-service.js +105 -0
- package/dist/services/tasks/task-types.d.ts +144 -0
- package/dist/services/tasks/task-types.js +2 -0
- package/dist/services/usage/index.d.ts +2 -0
- package/dist/services/usage/index.js +20 -0
- package/dist/services/usage/usage-service.d.ts +14 -0
- package/dist/services/usage/usage-service.js +68 -0
- package/dist/services/usage/usage-types.d.ts +133 -0
- package/dist/services/usage/usage-types.js +2 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.js +2 -0
- package/index.ts +12 -0
- package/jest.config.json +19 -0
- package/package.json +45 -0
- package/services/README.md +113 -0
- package/services/base/base-service.ts +230 -0
- package/services/base/index.ts +1 -0
- package/services/generation/generation-service.ts +81 -0
- package/services/generation/generation-types.ts +131 -0
- package/services/generation/index.ts +2 -0
- package/services/index.ts +22 -0
- package/services/projects/index.ts +2 -0
- package/services/projects/project-service.ts +67 -0
- package/services/projects/project-types.ts +108 -0
- package/services/repository-analysis/index.ts +2 -0
- package/services/repository-analysis/repository-service.ts +42 -0
- package/services/repository-analysis/repository-types.ts +99 -0
- package/services/tasks/index.ts +2 -0
- package/services/tasks/task-service.ts +143 -0
- package/services/tasks/task-types.ts +165 -0
- package/services/usage/index.ts +2 -0
- package/services/usage/usage-service.ts +96 -0
- package/services/usage/usage-types.ts +147 -0
- package/tsconfig.json +10 -0
- package/types.ts +51 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { TestService } from './test-service'
|
|
2
|
+
import { APIServiceConfig, AuthenticationMethod } from '../types'
|
|
3
|
+
|
|
4
|
+
describe('Authentication Priority System', () => {
|
|
5
|
+
describe('Priority Order', () => {
|
|
6
|
+
it('should always prefer database API key over other methods', () => {
|
|
7
|
+
const testCases = [
|
|
8
|
+
{
|
|
9
|
+
config: {
|
|
10
|
+
baseUrl: 'https://api.codeguide.app',
|
|
11
|
+
databaseApiKey: 'sk_test123',
|
|
12
|
+
apiKey: 'legacy_key',
|
|
13
|
+
userId: 'user123',
|
|
14
|
+
jwtToken: 'jwt_token',
|
|
15
|
+
},
|
|
16
|
+
expectedType: 'database-api-key',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
config: {
|
|
20
|
+
baseUrl: 'https://api.codeguide.app',
|
|
21
|
+
databaseApiKey: 'sk_test123',
|
|
22
|
+
jwtToken: 'jwt_token',
|
|
23
|
+
},
|
|
24
|
+
expectedType: 'database-api-key',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
config: {
|
|
28
|
+
baseUrl: 'https://api.codeguide.app',
|
|
29
|
+
databaseApiKey: 'sk_test123',
|
|
30
|
+
apiKey: 'legacy_key',
|
|
31
|
+
userId: 'user123',
|
|
32
|
+
},
|
|
33
|
+
expectedType: 'database-api-key',
|
|
34
|
+
},
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
testCases.forEach(({ config, expectedType }) => {
|
|
38
|
+
const service = new TestService(config)
|
|
39
|
+
const authMethod = service.getAuthenticationMethod()
|
|
40
|
+
expect(authMethod?.type).toBe(expectedType)
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should prefer legacy API key + user ID over JWT when no database key', () => {
|
|
45
|
+
const config: APIServiceConfig = {
|
|
46
|
+
baseUrl: 'https://api.codeguide.app',
|
|
47
|
+
apiKey: 'legacy_key',
|
|
48
|
+
userId: 'user123',
|
|
49
|
+
jwtToken: 'jwt_token',
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const service = new TestService(config)
|
|
53
|
+
const authMethod = service.getAuthenticationMethod()
|
|
54
|
+
|
|
55
|
+
expect(authMethod?.type).toBe('legacy-api-key')
|
|
56
|
+
expect(authMethod?.priority).toBe(2)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('should use JWT as fallback when only method available', () => {
|
|
60
|
+
const config: APIServiceConfig = {
|
|
61
|
+
baseUrl: 'https://api.codeguide.app',
|
|
62
|
+
jwtToken: 'jwt_token',
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const service = new TestService(config)
|
|
66
|
+
const authMethod = service.getAuthenticationMethod()
|
|
67
|
+
|
|
68
|
+
expect(authMethod?.type).toBe('clerk-jwt')
|
|
69
|
+
expect(authMethod?.priority).toBe(3)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe('Header Generation', () => {
|
|
74
|
+
it('should generate correct headers for database API key', () => {
|
|
75
|
+
const config: APIServiceConfig = {
|
|
76
|
+
baseUrl: 'https://api.codeguide.app',
|
|
77
|
+
databaseApiKey: 'sk_test123',
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const service = new TestService(config)
|
|
81
|
+
const authMethod = service.getAuthenticationMethod()
|
|
82
|
+
|
|
83
|
+
expect(authMethod?.headers).toEqual({
|
|
84
|
+
Authorization: 'Bearer sk_test123',
|
|
85
|
+
'Content-Type': 'application/json',
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('should generate correct headers for legacy API key', () => {
|
|
90
|
+
const config: APIServiceConfig = {
|
|
91
|
+
baseUrl: 'https://api.codeguide.app',
|
|
92
|
+
apiKey: 'legacy_key',
|
|
93
|
+
userId: 'user123',
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const service = new TestService(config)
|
|
97
|
+
const authMethod = service.getAuthenticationMethod()
|
|
98
|
+
|
|
99
|
+
expect(authMethod?.headers).toEqual({
|
|
100
|
+
'X-API-Key': 'legacy_key',
|
|
101
|
+
'X-User-ID': 'user123',
|
|
102
|
+
'Content-Type': 'application/json',
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('should generate correct headers for JWT token', () => {
|
|
107
|
+
const config: APIServiceConfig = {
|
|
108
|
+
baseUrl: 'https://api.codeguide.app',
|
|
109
|
+
jwtToken: 'jwt_token',
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const service = new TestService(config)
|
|
113
|
+
const authMethod = service.getAuthenticationMethod()
|
|
114
|
+
|
|
115
|
+
expect(authMethod?.headers).toEqual({
|
|
116
|
+
Authorization: 'Bearer jwt_token',
|
|
117
|
+
'Content-Type': 'application/json',
|
|
118
|
+
})
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('should generate headers for legacy API key without user ID', () => {
|
|
122
|
+
const config: APIServiceConfig = {
|
|
123
|
+
baseUrl: 'https://api.codeguide.app',
|
|
124
|
+
apiKey: 'legacy_key',
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const service = new TestService(config)
|
|
128
|
+
const authMethod = service.getAuthenticationMethod()
|
|
129
|
+
|
|
130
|
+
expect(authMethod?.headers).toEqual({
|
|
131
|
+
'X-API-Key': 'legacy_key',
|
|
132
|
+
'Content-Type': 'application/json',
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
describe('Validation Scenarios', () => {
|
|
138
|
+
it('should reject database API key without sk_ prefix', () => {
|
|
139
|
+
const invalidConfigs = [
|
|
140
|
+
{ databaseApiKey: 'test123' },
|
|
141
|
+
{ databaseApiKey: 'pk_test123' },
|
|
142
|
+
{ databaseApiKey: 'sktest123' },
|
|
143
|
+
{ databaseApiKey: '' },
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
invalidConfigs.forEach(config => {
|
|
147
|
+
const fullConfig: APIServiceConfig = {
|
|
148
|
+
baseUrl: 'https://api.codeguide.app',
|
|
149
|
+
...config,
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const service = new TestService(fullConfig)
|
|
153
|
+
const result = service.validateAuthentication()
|
|
154
|
+
|
|
155
|
+
expect(result.success).toBe(false)
|
|
156
|
+
expect(result.error).toContain('must start with "sk_"')
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it('should accept valid database API key formats', () => {
|
|
161
|
+
const validConfigs = ['sk_test123', 'sk_prod_abc123', 'sk_123456789', 'sk_live_xxx']
|
|
162
|
+
|
|
163
|
+
validConfigs.forEach(apiKey => {
|
|
164
|
+
const config: APIServiceConfig = {
|
|
165
|
+
baseUrl: 'https://api.codeguide.app',
|
|
166
|
+
databaseApiKey: apiKey,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const service = new TestService(config)
|
|
170
|
+
const result = service.validateAuthentication()
|
|
171
|
+
|
|
172
|
+
expect(result.success).toBe(true)
|
|
173
|
+
expect(result.method?.type).toBe('database-api-key')
|
|
174
|
+
})
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('should handle mixed authentication configurations', () => {
|
|
178
|
+
const mixedConfigs = [
|
|
179
|
+
{
|
|
180
|
+
config: {
|
|
181
|
+
baseUrl: 'https://api.codeguide.app',
|
|
182
|
+
apiKey: 'legacy_key',
|
|
183
|
+
jwtToken: 'jwt_token',
|
|
184
|
+
},
|
|
185
|
+
expectedType: 'legacy-api-key',
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
config: {
|
|
189
|
+
baseUrl: 'https://api.codeguide.app',
|
|
190
|
+
apiKey: 'legacy_key',
|
|
191
|
+
userId: 'user123',
|
|
192
|
+
databaseApiKey: 'sk_test123',
|
|
193
|
+
},
|
|
194
|
+
expectedType: 'database-api-key',
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
config: {
|
|
198
|
+
baseUrl: 'https://api.codeguide.app',
|
|
199
|
+
jwtToken: 'jwt_token',
|
|
200
|
+
databaseApiKey: 'invalid_key',
|
|
201
|
+
},
|
|
202
|
+
expectedType: 'clerk-jwt',
|
|
203
|
+
},
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
mixedConfigs.forEach(({ config, expectedType }) => {
|
|
207
|
+
const service = new TestService(config)
|
|
208
|
+
const result = service.validateAuthentication()
|
|
209
|
+
|
|
210
|
+
if (expectedType === 'database-api-key' && config.databaseApiKey === 'invalid_key') {
|
|
211
|
+
expect(result.success).toBe(false)
|
|
212
|
+
} else {
|
|
213
|
+
expect(result.success).toBe(true)
|
|
214
|
+
expect(result.method?.type).toBe(expectedType)
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
})
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
describe('Priority Consistency', () => {
|
|
221
|
+
it('should maintain consistent priority numbers', () => {
|
|
222
|
+
const config: APIServiceConfig = {
|
|
223
|
+
baseUrl: 'https://api.codeguide.app',
|
|
224
|
+
databaseApiKey: 'sk_test123',
|
|
225
|
+
apiKey: 'legacy_key',
|
|
226
|
+
userId: 'user123',
|
|
227
|
+
jwtToken: 'jwt_token',
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const service = new TestService(config)
|
|
231
|
+
const authMethod = service.getAuthenticationMethod()
|
|
232
|
+
|
|
233
|
+
expect(authMethod?.priority).toBe(1)
|
|
234
|
+
|
|
235
|
+
// Test other methods
|
|
236
|
+
const noDbConfig: APIServiceConfig = {
|
|
237
|
+
baseUrl: 'https://api.codeguide.app',
|
|
238
|
+
apiKey: 'legacy_key',
|
|
239
|
+
userId: 'user123',
|
|
240
|
+
jwtToken: 'jwt_token',
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const noDbService = new BaseService(noDbConfig)
|
|
244
|
+
const noDbAuthMethod = noDbService.getAuthenticationMethod()
|
|
245
|
+
|
|
246
|
+
expect(noDbAuthMethod?.priority).toBe(2)
|
|
247
|
+
|
|
248
|
+
const jwtOnlyConfig: APIServiceConfig = {
|
|
249
|
+
baseUrl: 'https://api.codeguide.app',
|
|
250
|
+
jwtToken: 'jwt_token',
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const jwtOnlyService = new BaseService(jwtOnlyConfig)
|
|
254
|
+
const jwtOnlyAuthMethod = jwtOnlyService.getAuthenticationMethod()
|
|
255
|
+
|
|
256
|
+
expect(jwtOnlyAuthMethod?.priority).toBe(3)
|
|
257
|
+
})
|
|
258
|
+
})
|
|
259
|
+
})
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { CodeGuide } from '../codeguide'
|
|
2
|
+
import { APIServiceConfig, CodeGuideOptions } from '../types'
|
|
3
|
+
import axios from 'axios'
|
|
4
|
+
import MockAdapter from 'axios-mock-adapter'
|
|
5
|
+
|
|
6
|
+
// Mock the generation service
|
|
7
|
+
jest.mock('../services/generation/generation-service', () => ({
|
|
8
|
+
GenerationService: jest.fn().mockImplementation(() => ({
|
|
9
|
+
refinePrompt: jest.fn(),
|
|
10
|
+
})),
|
|
11
|
+
}))
|
|
12
|
+
|
|
13
|
+
describe('CodeGuide', () => {
|
|
14
|
+
let mockAxios: MockAdapter
|
|
15
|
+
let codeguide: CodeGuide
|
|
16
|
+
let config: APIServiceConfig
|
|
17
|
+
let options: CodeGuideOptions
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
mockAxios = new MockAdapter(axios)
|
|
21
|
+
config = {
|
|
22
|
+
baseUrl: 'https://api.codeguide.app',
|
|
23
|
+
databaseApiKey: 'sk_test123',
|
|
24
|
+
}
|
|
25
|
+
options = {
|
|
26
|
+
language: 'typescript',
|
|
27
|
+
context: 'CLI testing',
|
|
28
|
+
verbose: false,
|
|
29
|
+
}
|
|
30
|
+
codeguide = new CodeGuide(config, options)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
mockAxios.restore()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
describe('Constructor', () => {
|
|
38
|
+
it('should initialize all services', () => {
|
|
39
|
+
expect(codeguide.generation).toBeDefined()
|
|
40
|
+
expect(codeguide.projects).toBeDefined()
|
|
41
|
+
expect(codeguide.usage).toBeDefined()
|
|
42
|
+
expect(codeguide.repositoryAnalysis).toBeDefined()
|
|
43
|
+
expect(codeguide.tasks).toBeDefined()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('should initialize with default options', () => {
|
|
47
|
+
const simpleCodeguide = new CodeGuide(config)
|
|
48
|
+
expect(simpleCodeguide).toBeDefined()
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('getGuidance', () => {
|
|
53
|
+
it('should get guidance successfully', async () => {
|
|
54
|
+
const prompt = 'How do I create a React component?'
|
|
55
|
+
const mockResponse = {
|
|
56
|
+
refined_prompt:
|
|
57
|
+
'To create a React component, you can use either functional components with hooks or class components.',
|
|
58
|
+
original_prompt: prompt,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
mockAxios.onPost('/v1/generation/refine-prompt').reply(200, mockResponse)
|
|
62
|
+
|
|
63
|
+
const result = await codeguide.getGuidance(prompt)
|
|
64
|
+
|
|
65
|
+
expect(result).toEqual({
|
|
66
|
+
id: expect.any(String),
|
|
67
|
+
response: mockResponse.refined_prompt,
|
|
68
|
+
timestamp: expect.any(String),
|
|
69
|
+
language: 'typescript',
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('should include language in request when provided', async () => {
|
|
74
|
+
const prompt = 'How do I create a React component?'
|
|
75
|
+
const mockResponse = {
|
|
76
|
+
refined_prompt: 'Here is how to create a React component in TypeScript...',
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
mockAxios.onPost('/v1/generation/refine-prompt').reply(200, mockResponse)
|
|
80
|
+
|
|
81
|
+
await codeguide.getGuidance(prompt)
|
|
82
|
+
|
|
83
|
+
const request = mockAxios.history.post[0]
|
|
84
|
+
const requestData = JSON.parse(request.data)
|
|
85
|
+
|
|
86
|
+
expect(requestData.language).toBe('typescript')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('should include context in request when provided', async () => {
|
|
90
|
+
const prompt = 'How do I create a React component?'
|
|
91
|
+
const mockResponse = {
|
|
92
|
+
refined_prompt: 'Here is how to create a React component...',
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
mockAxios.onPost('/v1/generation/refine-prompt').reply(200, mockResponse)
|
|
96
|
+
|
|
97
|
+
await codeguide.getGuidance(prompt)
|
|
98
|
+
|
|
99
|
+
const request = mockAxios.history.post[0]
|
|
100
|
+
const requestData = JSON.parse(request.data)
|
|
101
|
+
|
|
102
|
+
expect(requestData.context).toBe('CLI testing')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('should not include optional fields when not provided', async () => {
|
|
106
|
+
const simpleOptions: CodeGuideOptions = {}
|
|
107
|
+
const simpleCodeguide = new CodeGuide(config, simpleOptions)
|
|
108
|
+
const prompt = 'How do I create a React component?'
|
|
109
|
+
const mockResponse = {
|
|
110
|
+
refined_prompt: 'Here is how to create a React component...',
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
mockAxios.onPost('/v1/generation/refine-prompt').reply(200, mockResponse)
|
|
114
|
+
|
|
115
|
+
await simpleCodeguide.getGuidance(prompt)
|
|
116
|
+
|
|
117
|
+
const request = mockAxios.history.post[0]
|
|
118
|
+
const requestData = JSON.parse(request.data)
|
|
119
|
+
|
|
120
|
+
expect(requestData).not.toHaveProperty('language')
|
|
121
|
+
expect(requestData).not.toHaveProperty('context')
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('should handle API errors gracefully', async () => {
|
|
125
|
+
const prompt = 'How do I create a React component?'
|
|
126
|
+
|
|
127
|
+
mockAxios.onPost('/v1/generation/refine-prompt').reply(400, {
|
|
128
|
+
detail: 'Invalid prompt format',
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
await expect(codeguide.getGuidance(prompt)).rejects.toThrow(
|
|
132
|
+
'API Error: Invalid prompt format'
|
|
133
|
+
)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('should log request and response when verbose mode is enabled', async () => {
|
|
137
|
+
const verboseOptions: CodeGuideOptions = {
|
|
138
|
+
verbose: true,
|
|
139
|
+
}
|
|
140
|
+
const verboseCodeguide = new CodeGuide(config, verboseOptions)
|
|
141
|
+
const prompt = 'How do I create a React component?'
|
|
142
|
+
const mockResponse = {
|
|
143
|
+
refined_prompt: 'Here is how to create a React component...',
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Mock console.log to verify it's called
|
|
147
|
+
const consoleSpy = jest.spyOn(console, 'log').mockImplementation()
|
|
148
|
+
|
|
149
|
+
mockAxios.onPost('/v1/generation/refine-prompt').reply(200, mockResponse)
|
|
150
|
+
|
|
151
|
+
await verboseCodeguide.getGuidance(prompt)
|
|
152
|
+
|
|
153
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
154
|
+
'Sending request:',
|
|
155
|
+
expect.stringContaining('user_prompt')
|
|
156
|
+
)
|
|
157
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
158
|
+
'Received response:',
|
|
159
|
+
expect.stringContaining('refined_prompt')
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
consoleSpy.mockRestore()
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
describe('isHealthy', () => {
|
|
167
|
+
it('should return true when API is healthy', async () => {
|
|
168
|
+
mockAxios.onGet('/v1/usage/health').reply(200, {
|
|
169
|
+
status: 'healthy',
|
|
170
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
171
|
+
version: '1.0.0',
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
const result = await codeguide.isHealthy()
|
|
175
|
+
|
|
176
|
+
expect(result).toBe(true)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
it('should return false when API is not healthy', async () => {
|
|
180
|
+
mockAxios.onGet('/v1/usage/health').reply(200, {
|
|
181
|
+
status: 'unhealthy',
|
|
182
|
+
timestamp: '2024-01-01T00:00:00Z',
|
|
183
|
+
version: '1.0.0',
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
const result = await codeguide.isHealthy()
|
|
187
|
+
|
|
188
|
+
expect(result).toBe(false)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('should return false when health check fails', async () => {
|
|
192
|
+
mockAxios.onGet('/v1/usage/health').reply(500)
|
|
193
|
+
|
|
194
|
+
const result = await codeguide.isHealthy()
|
|
195
|
+
|
|
196
|
+
expect(result).toBe(false)
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
describe('setOptions', () => {
|
|
201
|
+
it('should update options partially', () => {
|
|
202
|
+
const initialOptions = { ...options }
|
|
203
|
+
expect((codeguide as any).options).toEqual(initialOptions)
|
|
204
|
+
|
|
205
|
+
const newOptions: Partial<CodeGuideOptions> = {
|
|
206
|
+
language: 'javascript',
|
|
207
|
+
verbose: true,
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
codeguide.setOptions(newOptions)
|
|
211
|
+
|
|
212
|
+
expect((codeguide as any).options).toEqual({
|
|
213
|
+
language: 'javascript',
|
|
214
|
+
context: 'CLI testing',
|
|
215
|
+
verbose: true,
|
|
216
|
+
})
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('should add new options', () => {
|
|
220
|
+
const newOptions: Partial<CodeGuideOptions> = {
|
|
221
|
+
context: 'Updated context',
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
codeguide.setOptions(newOptions)
|
|
225
|
+
|
|
226
|
+
expect((codeguide as any).options.context).toBe('Updated context')
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
it('should handle empty options object', () => {
|
|
230
|
+
const originalOptions = { ...(codeguide as any).options }
|
|
231
|
+
|
|
232
|
+
codeguide.setOptions({})
|
|
233
|
+
|
|
234
|
+
expect((codeguide as any).options).toEqual(originalOptions)
|
|
235
|
+
})
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
describe('Service Access', () => {
|
|
239
|
+
it('should provide access to all services', () => {
|
|
240
|
+
expect(codeguide.generation).toBeDefined()
|
|
241
|
+
expect(codeguide.projects).toBeDefined()
|
|
242
|
+
expect(codeguide.usage).toBeDefined()
|
|
243
|
+
expect(codeguide.repositoryAnalysis).toBeDefined()
|
|
244
|
+
expect(codeguide.tasks).toBeDefined()
|
|
245
|
+
|
|
246
|
+
// Verify services are properly configured with the same auth config
|
|
247
|
+
expect((codeguide.generation as any).config).toEqual(config)
|
|
248
|
+
expect((codeguide.projects as any).config).toEqual(config)
|
|
249
|
+
expect((codeguide.usage as any).config).toEqual(config)
|
|
250
|
+
expect((codeguide.repositoryAnalysis as any).config).toEqual(config)
|
|
251
|
+
expect((codeguide.tasks as any).config).toEqual(config)
|
|
252
|
+
})
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
describe('Different Authentication Methods', () => {
|
|
256
|
+
it('should work with legacy API key authentication', () => {
|
|
257
|
+
const legacyConfig: APIServiceConfig = {
|
|
258
|
+
baseUrl: 'https://api.codeguide.app',
|
|
259
|
+
apiKey: 'legacy_key',
|
|
260
|
+
userId: 'user123',
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const legacyCodeguide = new CodeGuide(legacyConfig, options)
|
|
264
|
+
|
|
265
|
+
expect(legacyCodeguide.generation).toBeDefined()
|
|
266
|
+
expect(legacyCodeguide.usage).toBeDefined()
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
it('should work with JWT authentication', () => {
|
|
270
|
+
const jwtConfig: APIServiceConfig = {
|
|
271
|
+
baseUrl: 'https://api.codeguide.app',
|
|
272
|
+
jwtToken: 'jwt_token',
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const jwtCodeguide = new CodeGuide(jwtConfig, options)
|
|
276
|
+
|
|
277
|
+
expect(jwtCodeguide.generation).toBeDefined()
|
|
278
|
+
expect(jwtCodeguide.usage).toBeDefined()
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
it('should work with database API key authentication', () => {
|
|
282
|
+
const dbConfig: APIServiceConfig = {
|
|
283
|
+
baseUrl: 'https://api.codeguide.app',
|
|
284
|
+
databaseApiKey: 'sk_test123',
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const dbCodeguide = new CodeGuide(dbConfig, options)
|
|
288
|
+
|
|
289
|
+
expect(dbCodeguide.generation).toBeDefined()
|
|
290
|
+
expect(dbCodeguide.usage).toBeDefined()
|
|
291
|
+
})
|
|
292
|
+
})
|
|
293
|
+
})
|