Skip to content

Commit d2afea7

Browse files
committed
fix: stabilize cli tests and web trace parsing
1 parent 0a70a15 commit d2afea7

File tree

6 files changed

+58
-46
lines changed

6 files changed

+58
-46
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,8 @@ jobs:
8585
package:
8686
[
8787
.agents,
88-
backend,
8988
cli,
9089
common,
91-
npm-app,
9290
packages/agent-runtime,
9391
packages/billing,
9492
packages/internal,
@@ -97,10 +95,8 @@ jobs:
9795
]
9896
include:
9997
- package: .agents
100-
- package: backend
10198
- package: cli
10299
- package: common
103-
- package: npm-app
104100
- package: packages/agent-runtime
105101
- package: packages/billing
106102
- package: packages/internal
@@ -180,10 +176,8 @@ jobs:
180176
package:
181177
[
182178
.agents,
183-
backend,
184179
cli,
185180
common,
186-
npm-app,
187181
packages/agent-runtime,
188182
packages/billing,
189183
packages/internal,
@@ -192,10 +186,8 @@ jobs:
192186
]
193187
include:
194188
- package: .agents
195-
- package: backend
196189
- package: cli
197190
- package: common
198-
- package: npm-app
199191
- package: packages/agent-runtime
200192
- package: packages/billing
201193
- package: packages/internal

cli/src/__tests__/e2e/logout-relogin-flow.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
import { setProjectRoot } from '../../project-files'
2121

2222
import type * as AuthModule from '../../utils/auth'
23+
import type * as CodebuffApiModule from '../../utils/codebuff-api'
2324

2425
type User = AuthModule.User
2526

@@ -63,8 +64,16 @@ describe('Logout and Re-login helpers', () => {
6364
)
6465
}
6566

67+
const mockLogoutApi = () => {
68+
const apiModule = require('../../utils/codebuff-api') as typeof CodebuffApiModule
69+
spyOn(apiModule, 'getApiClient').mockReturnValue({
70+
logout: async () => ({ ok: true, status: 200 }),
71+
} as any)
72+
}
73+
6674
test('logoutUser removes credentials file and returns true', async () => {
6775
mockConfigPaths()
76+
mockLogoutApi()
6877
saveUserCredentials(ORIGINAL_USER)
6978

7079
const credentialsPath = path.join(tempConfigDir, 'credentials.json')
@@ -77,6 +86,7 @@ describe('Logout and Re-login helpers', () => {
7786

7887
test('re-login can persist new credentials after logout', async () => {
7988
mockConfigPaths()
89+
mockLogoutApi()
8090

8191
saveUserCredentials(ORIGINAL_USER)
8292
const firstLoaded = getUserCredentials()

cli/src/hooks/__tests__/use-user-details-query.test.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { describe, test, expect, mock, beforeEach, afterEach } from 'bun:test'
1+
import { describe, test, expect, mock, beforeEach, afterEach, spyOn } from 'bun:test'
22

33
import { createMockApiClient } from '../../__tests__/helpers/mock-api-client'
44
import { fetchUserDetails } from '../use-user-details-query'
55

66
import type { Logger } from '@codebuff/common/types/contracts/logger'
7+
import type * as CodebuffApiModule from '../../utils/codebuff-api'
78

89
describe('fetchUserDetails', () => {
910
const mockLogger: Logger = {
@@ -179,18 +180,29 @@ describe('fetchUserDetails', () => {
179180
})
180181

181182
describe('environment validation', () => {
182-
test('throws error when NEXT_PUBLIC_CODEBUFF_APP_URL is not set', async () => {
183-
delete process.env.NEXT_PUBLIC_CODEBUFF_APP_URL
183+
test('uses shared API client when apiClient is not provided', async () => {
184+
const meMock = mock(() =>
185+
Promise.resolve({
186+
ok: true,
187+
status: 200,
188+
data: { email: 'test@example.com' },
189+
}),
190+
)
191+
const apiClient = createMockApiClient({ me: meMock })
192+
193+
const apiModule = require('../../utils/codebuff-api') as typeof CodebuffApiModule
194+
const setTokenSpy = spyOn(apiModule, 'setApiClientAuthToken')
195+
spyOn(apiModule, 'getApiClient').mockReturnValue(apiClient as any)
184196

185-
// When no apiClient is provided and env is not set, createCodebuffApiClient
186-
// will throw due to missing baseUrl (or we test directly)
187197
await expect(
188198
fetchUserDetails({
189199
authToken: 'valid-token',
190200
fields: ['email'] as const,
191201
logger: mockLogger,
192202
}),
193-
).rejects.toThrow()
203+
).resolves.toEqual({ email: 'test@example.com' })
204+
205+
expect(setTokenSpy).toHaveBeenCalledWith('valid-token')
194206
})
195207
})
196208
})

common/src/util/xml-parser.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Parses XML content for a tool call into a structured object with only string values.
3+
* Example input:
4+
* <type>click</type>
5+
* <selector>#button</selector>
6+
* <timeout>5000</timeout>
7+
*/
8+
export function parseToolCallXml(xmlString: string): Record<string, string> {
9+
if (!xmlString.trim()) return {}
10+
11+
const result: Record<string, string> = {}
12+
const tagPattern = /<(\w+)>([\s\S]*?)<\/\1>/g
13+
let match
14+
15+
while ((match = tagPattern.exec(xmlString)) !== null) {
16+
const [, key, rawValue] = match
17+
18+
// Remove leading/trailing whitespace but preserve internal whitespace
19+
const value = rawValue.replace(/^\s+|\s+$/g, '')
20+
21+
// Assign all values as strings
22+
result[key] = value
23+
}
24+
25+
return result
26+
}
27+

packages/internal/src/utils/xml-parser.ts

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,5 @@
1-
/**
2-
* Shared XML parsing utilities for tool calls
3-
* Used by both backend and web applications
4-
*/
5-
6-
/**
7-
* Parses XML content for a tool call into a structured object with only string values.
8-
* Example input:
9-
* <type>click</type>
10-
* <selector>#button</selector>
11-
* <timeout>5000</timeout>
12-
*/
13-
export function parseToolCallXml(xmlString: string): Record<string, string> {
14-
if (!xmlString.trim()) return {}
15-
16-
const result: Record<string, string> = {}
17-
const tagPattern = /<(\w+)>([\s\S]*?)<\/\1>/g
18-
let match
19-
20-
while ((match = tagPattern.exec(xmlString)) !== null) {
21-
const [_, key, rawValue] = match
22-
23-
// Remove leading/trailing whitespace but preserve internal whitespace
24-
const value = rawValue.replace(/^\s+|\s+$/g, '')
25-
26-
// Assign all values as strings
27-
result[key] = value
28-
}
29-
30-
return result
31-
}
1+
// Re-exported from @codebuff/common to keep it browser-safe and avoid duplication.
2+
export { parseToolCallXml } from '@codebuff/common/util/xml-parser'
323

334
/**
345
* Tool result part interface

web/src/app/admin/traces/utils/trace-processing.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { parseToolCallXml } from '@codebuff/internal'
1+
import { parseToolCallXml } from '@codebuff/common/util/xml-parser'
22

33
import type { TraceMessage } from '@/app/api/admin/traces/[clientRequestId]/messages/route'
44
import type { TimelineEvent } from '@/app/api/admin/traces/[clientRequestId]/timeline/route'

0 commit comments

Comments
 (0)