test(core): cover the parseSchema contract
Assert add_connection advertises fullSchema as its inputSchema (never the refined schema) and applies an optional parseSchema in the handler: a refinement rejection surfaces as an error and skips registry.add, while a passing config persists. Locks the wire/parse split at the core level.
This commit is contained in:
1 parent
63bb2a5c99
commit
82d2392e31
1 file changed
+34
-2
@@ -98,7 +98,7 @@ describe('registerConnectionTools', () => {
|
||||
let registry: FakeRegistry
|
||||
let manager: FakeManager
|
||||
let handlers: Map<string, Handler>
|
||||
let configs: Map<string, { description?: string }>
|
||||
let configs: Map<string, { description?: string; inputSchema?: unknown }>
|
||||
|
||||
const invoke = (name: string, args: Record<string, unknown> = {}): Promise<CallToolResult> => {
|
||||
const handler = handlers.get(name)
|
||||
@@ -113,7 +113,11 @@ describe('registerConnectionTools', () => {
|
||||
handlers = new Map()
|
||||
configs = new Map()
|
||||
vi.spyOn(server, 'registerTool').mockImplementation(
|
||||
(name: string, config: { description?: string }, handler: unknown) => {
|
||||
(
|
||||
name: string,
|
||||
config: { description?: string; inputSchema?: unknown },
|
||||
handler: unknown
|
||||
) => {
|
||||
configs.set(name, config)
|
||||
handlers.set(name, handler as Handler)
|
||||
return {
|
||||
@@ -212,6 +216,34 @@ describe('registerConnectionTools', () => {
|
||||
expect(text(result)).toContain('already exists')
|
||||
})
|
||||
|
||||
it('add_connection advertises fullSchema and applies parseSchema in the handler', async () => {
|
||||
const parseSchema = schema.superRefine((c, ctx) => {
|
||||
if (c.host === 'bad') {
|
||||
ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'bad host' })
|
||||
}
|
||||
})
|
||||
registry.add.mockImplementation((config: TestConfig) => resolved(config))
|
||||
register({ parseSchema })
|
||||
|
||||
// The advertised wire schema is always fullSchema, never the refined one
|
||||
// (a ZodEffects has no .shape and would publish an empty inputSchema).
|
||||
expect(configs.get('add_connection')?.inputSchema).toBe(schema)
|
||||
|
||||
const rejected = await invoke('add_connection', { name: 'x', type: 'mysql', host: 'bad' })
|
||||
expect(rejected.isError).toBe(true)
|
||||
expect(text(rejected)).toContain('bad host')
|
||||
expect(registry.add).not.toHaveBeenCalled()
|
||||
|
||||
const accepted = await invoke('add_connection', { name: 'y', type: 'mysql', host: 'good' })
|
||||
expect(accepted.isError).toBeFalsy()
|
||||
expect(registry.add).toHaveBeenCalledWith({
|
||||
name: 'y',
|
||||
type: 'mysql',
|
||||
host: 'good',
|
||||
readonly: false
|
||||
})
|
||||
})
|
||||
|
||||
it('update_connection patches, invalidates the cache and returns the public view', async () => {
|
||||
registry.update.mockReturnValue(
|
||||
resolved({ name: 'c', type: 'postgres', host: 'new', readonly: false })
|
||||
|
||||
Reference in new issue
Block a user